Example #1
0
        public void TestPointerType()
        {
            NamedTypeSymbol pointedAtType = new MockNamedTypeSymbol("TestClass", Enumerable.Empty<Symbol>());   // this can be any type.

            PointerTypeSymbol pts1 = new PointerTypeSymbol(pointedAtType);
            Assert.Same(pointedAtType, pts1.PointedAtType);
            Assert.Equal(SymbolKind.PointerType, pts1.Kind);
            Assert.False(pts1.IsReferenceType);
            Assert.True(pts1.IsValueType);
            Assert.Equal("TestClass*", pts1.ToTestDisplayString());
        }
Example #2
0
        private bool Equals(PointerTypeSymbol other, bool ignoreCustomModifiers, bool ignoreDynamic)
        {
            if (ReferenceEquals(this, other))
            {
                return(true);
            }

            if ((object)other == null || !other.pointedAtType.Equals(pointedAtType, ignoreCustomModifiers, ignoreDynamic))
            {
                return(false);
            }

            if (!ignoreCustomModifiers)
            {
                // Make sure custom modifiers are the same.
                var mod      = this.CustomModifiers;
                var otherMod = other.CustomModifiers;

                int count = mod.Length;

                if (count != otherMod.Length)
                {
                    return(false);
                }

                for (int i = 0; i < count; i++)
                {
                    if (!mod[i].Equals(otherMod[i]))
                    {
                        return(false);
                    }
                }
            }

            return(true);
        }
        internal sealed override TypeSymbol GetFieldType(ConsList<FieldSymbol> fieldsBeingBound)
        {
            Debug.Assert(fieldsBeingBound != null);

            if ((object)_lazyType != null)
            {
                return _lazyType;
            }

            var declarator = VariableDeclaratorNode;
            var fieldSyntax = GetFieldDeclaration(declarator);
            var typeSyntax = fieldSyntax.Declaration.Type;

            var compilation = this.DeclaringCompilation;

            var diagnostics = DiagnosticBag.GetInstance();
            TypeSymbol type;

            // When we have multiple declarators, we report the type diagnostics on only the first.
            DiagnosticBag diagnosticsForFirstDeclarator = DiagnosticBag.GetInstance();

            Symbol associatedPropertyOrEvent = this.AssociatedSymbol;
            if ((object)associatedPropertyOrEvent != null && associatedPropertyOrEvent.Kind == SymbolKind.Event)
            {
                EventSymbol @event = (EventSymbol)associatedPropertyOrEvent;
                if (@event.IsWindowsRuntimeEvent)
                {
                    NamedTypeSymbol tokenTableType = this.DeclaringCompilation.GetWellKnownType(WellKnownType.System_Runtime_InteropServices_WindowsRuntime_EventRegistrationTokenTable_T);
                    Binder.ReportUseSiteDiagnostics(tokenTableType, diagnosticsForFirstDeclarator, this.ErrorLocation);

                    // CONSIDER: Do we want to guard against the possibility that someone has created their own EventRegistrationTokenTable<T>
                    // type that has additional generic constraints?
                    type = tokenTableType.Construct(@event.Type);
                }
                else
                {
                    type = @event.Type;
                }
            }
            else
            {
                var binderFactory = compilation.GetBinderFactory(SyntaxTree);
                var binder = binderFactory.GetBinder(typeSyntax);

                binder = binder.WithContainingMemberOrLambda(this);
                if (!ContainingType.IsScriptClass)
                {
                    type = binder.BindType(typeSyntax, diagnosticsForFirstDeclarator);
                    if (IsFixed)
                    {
                        type = new PointerTypeSymbol(type);
                    }
                }
                else
                {
                    bool isVar;
                    type = binder.BindType(typeSyntax, diagnostics, out isVar);

                    Debug.Assert((object)type != null || isVar);

                    if (isVar)
                    {
                        if (this.IsConst)
                        {
                            diagnosticsForFirstDeclarator.Add(ErrorCode.ERR_ImplicitlyTypedVariableCannotBeConst, typeSyntax.Location);
                        }

                        if (fieldsBeingBound.ContainsReference(this))
                        {
                            diagnostics.Add(ErrorCode.ERR_RecursivelyTypedVariable, this.ErrorLocation, this);
                            type = null;
                        }
                        else if (fieldSyntax.Declaration.Variables.Count > 1)
                        {
                            diagnosticsForFirstDeclarator.Add(ErrorCode.ERR_ImplicitlyTypedVariableMultipleDeclarator, typeSyntax.Location);
                        }
                        else
                        {
                            fieldsBeingBound = new ConsList<FieldSymbol>(this, fieldsBeingBound);

                            var initializerBinder = new ImplicitlyTypedFieldBinder(binder, fieldsBeingBound);
                            var initializerOpt = initializerBinder.BindInferredVariableInitializer(diagnostics, declarator.Initializer, declarator);

                            if (initializerOpt != null)
                            {
                                if ((object)initializerOpt.Type != null && !initializerOpt.Type.IsErrorType())
                                {
                                    type = initializerOpt.Type;
                                }

                                _lazyFieldTypeInferred = 1;
                            }
                        }

                        if ((object)type == null)
                        {
                            type = binder.CreateErrorType("var");
                        }
                    }
                }

                if (IsFixed)
                {
                    if (ContainingType.TypeKind != TypeKind.Struct)
                    {
                        diagnostics.Add(ErrorCode.ERR_FixedNotInStruct, ErrorLocation);
                    }

                    var elementType = ((PointerTypeSymbol)type).PointedAtType;
                    int elementSize = elementType.FixedBufferElementSizeInBytes();
                    if (elementSize == 0)
                    {
                        var loc = typeSyntax.Location;
                        diagnostics.Add(ErrorCode.ERR_IllegalFixedType, loc);
                    }

                    if (!binder.InUnsafeRegion)
                    {
                        diagnosticsForFirstDeclarator.Add(ErrorCode.ERR_UnsafeNeeded, declarator.Location);
                    }
                }
            }

            // update the lazyType only if it contains value last seen by the current thread:
            if ((object)Interlocked.CompareExchange(ref _lazyType, type, null) == null)
            {
                TypeChecks(type, fieldSyntax, declarator, diagnostics);

                // CONSIDER: SourceEventFieldSymbol would like to suppress these diagnostics.
                compilation.DeclarationDiagnostics.AddRange(diagnostics);

                bool isFirstDeclarator = fieldSyntax.Declaration.Variables[0] == declarator;
                if (isFirstDeclarator)
                {
                    compilation.DeclarationDiagnostics.AddRange(diagnosticsForFirstDeclarator);
                }

                state.NotePartComplete(CompletionPart.Type);
            }

            diagnostics.Free();
            diagnosticsForFirstDeclarator.Free();
            return _lazyType;
        }
Example #4
0
        private PointerTypeSymbol TransformPointerType(PointerTypeSymbol pointerType)
        {
            var flag = ConsumeFlag();
            Debug.Assert(!flag);

            if (!HandleCustomModifiers(pointerType.CustomModifiers.Length))
            {
                return null;
            }

            TypeSymbol transformedPointedAtType = TransformType(pointerType.PointedAtType);
            if ((object)transformedPointedAtType == null)
            {
                return null;
            }

            return transformedPointedAtType == pointerType.PointedAtType ?
                pointerType :
                new PointerTypeSymbol(transformedPointedAtType, pointerType.CustomModifiers);
        }
 private void GetPointerComparisonOperators(
     BinaryOperatorKind kind,
     ArrayBuilder<BinaryOperatorSignature> operators)
 {
     switch (kind)
     {
         case BinaryOperatorKind.Equal:
         case BinaryOperatorKind.NotEqual:
         case BinaryOperatorKind.GreaterThan:
         case BinaryOperatorKind.LessThan:
         case BinaryOperatorKind.GreaterThanOrEqual:
         case BinaryOperatorKind.LessThanOrEqual:
             var voidPointerType = new PointerTypeSymbol(Compilation.GetSpecialType(SpecialType.System_Void));
             operators.Add(new BinaryOperatorSignature(kind | BinaryOperatorKind.Pointer, voidPointerType, voidPointerType, Compilation.GetSpecialType(SpecialType.System_Boolean)));
             break;
     }
 }
Example #6
0
        public void FixedSemanticModelSymbolInfoConversions()
        {
            var text = @"
using System;

unsafe class C
{
    char c = 'a';
    char[] a = new char[1];

    static void Main()
    {
        C c = new C();
        fixed (void* p = &c.c, q = c.a, r = ""hello"")
        {
        }
    }
}
";
            var compilation = CreateCompilationWithMscorlib(text, options: TestOptions.UnsafeReleaseDll);
            var tree = compilation.SyntaxTrees.Single();
            var model = compilation.GetSemanticModel(tree);

            var stringSymbol = compilation.GetSpecialType(SpecialType.System_String);
            var charSymbol = compilation.GetSpecialType(SpecialType.System_Char);
            var charPointerSymbol = new PointerTypeSymbol(charSymbol);
            var voidSymbol = compilation.GetSpecialType(SpecialType.System_Void);
            var voidPointerSymbol = new PointerTypeSymbol(voidSymbol);

            const int numSymbols = 3;
            var declarators = tree.GetCompilationUnitRoot().DescendantNodes().OfType<VariableDeclaratorSyntax>().Reverse().Take(numSymbols).Reverse().ToArray();
            var initializerSummaries = declarators.Select(syntax => model.GetSemanticInfoSummary(syntax.Initializer.Value)).ToArray();

            for (int i = 0; i < numSymbols; i++)
            {
                var summary = initializerSummaries[i];
                Assert.Equal(0, summary.CandidateSymbols.Length);
                Assert.Equal(CandidateReason.None, summary.CandidateReason);
                Assert.Equal(0, summary.MethodGroup.Length);
                Assert.Null(summary.Alias);
            }

            var summary0 = initializerSummaries[0];
            Assert.Null(summary0.Symbol);
            Assert.Equal(charPointerSymbol, summary0.Type);
            Assert.Equal(voidPointerSymbol, summary0.ConvertedType);
            Assert.Equal(Conversion.PointerToVoid, summary0.ImplicitConversion);

            var summary1 = initializerSummaries[1];
            var arraySymbol = compilation.GlobalNamespace.GetMember<TypeSymbol>("C").GetMember<FieldSymbol>("a");
            Assert.Equal(arraySymbol, summary1.Symbol);
            Assert.Equal(arraySymbol.Type, summary1.Type);
            Assert.Equal(summary1.Type, summary1.ConvertedType);
            Assert.Equal(Conversion.Identity, summary1.ImplicitConversion);

            var summary2 = initializerSummaries[2];
            Assert.Null(summary2.Symbol);
            Assert.Equal(stringSymbol, summary2.Type);
            Assert.Equal(summary2.Type, summary2.ConvertedType);
            Assert.Equal(Conversion.Identity, summary2.ImplicitConversion);
        }
Example #7
0
        public void PointerElementAccessSemanticModelAPIs()
        {
            var text = @"
unsafe class C
{
    void M()
    {
        const int size = 3;
        fixed(int* p = new int[size])
        {
            for (int i = 0; i < size; i++)
            {
                p[i] = i * i;
            }
        }
    }
}
";
            var compilation = CreateCompilationWithMscorlib(text, options: TestOptions.UnsafeReleaseDll);
            var tree = compilation.SyntaxTrees.Single();
            var model = compilation.GetSemanticModel(tree);

            var syntax = tree.GetCompilationUnitRoot().DescendantNodes().OfType<ElementAccessExpressionSyntax>().Single();
            Assert.Equal(SyntaxKind.ElementAccessExpression, syntax.Kind());

            var receiverSyntax = syntax.Expression;
            var indexSyntax = syntax.ArgumentList.Arguments.Single().Expression;
            var accessSyntax = syntax;

            var intType = compilation.GetSpecialType(SpecialType.System_Int32);
            var intPointerType = new PointerTypeSymbol(intType);

            var receiverSummary = model.GetSemanticInfoSummary(receiverSyntax);
            var receiverSymbol = receiverSummary.Symbol;
            Assert.Equal(SymbolKind.Local, receiverSymbol.Kind);
            Assert.Equal(intPointerType, ((LocalSymbol)receiverSymbol).Type);
            Assert.Equal("p", receiverSymbol.Name);
            Assert.Equal(CandidateReason.None, receiverSummary.CandidateReason);
            Assert.Equal(0, receiverSummary.CandidateSymbols.Length);
            Assert.Equal(intPointerType, receiverSummary.Type);
            Assert.Equal(intPointerType, receiverSummary.ConvertedType);
            Assert.Equal(ConversionKind.Identity, receiverSummary.ImplicitConversion.Kind);
            Assert.Equal(0, receiverSummary.MethodGroup.Length);

            var indexSummary = model.GetSemanticInfoSummary(indexSyntax);
            var indexSymbol = indexSummary.Symbol;
            Assert.Equal(SymbolKind.Local, indexSymbol.Kind);
            Assert.Equal(intType, ((LocalSymbol)indexSymbol).Type);
            Assert.Equal("i", indexSymbol.Name);
            Assert.Equal(CandidateReason.None, indexSummary.CandidateReason);
            Assert.Equal(0, indexSummary.CandidateSymbols.Length);
            Assert.Equal(intType, indexSummary.Type);
            Assert.Equal(intType, indexSummary.ConvertedType);
            Assert.Equal(ConversionKind.Identity, indexSummary.ImplicitConversion.Kind);
            Assert.Equal(0, indexSummary.MethodGroup.Length);

            var accessSummary = model.GetSemanticInfoSummary(accessSyntax);
            Assert.Null(accessSummary.Symbol);
            Assert.Equal(CandidateReason.None, accessSummary.CandidateReason);
            Assert.Equal(0, accessSummary.CandidateSymbols.Length);
            Assert.Equal(intType, accessSummary.Type);
            Assert.Equal(intType, accessSummary.ConvertedType);
            Assert.Equal(ConversionKind.Identity, accessSummary.ImplicitConversion.Kind);
            Assert.Equal(0, accessSummary.MethodGroup.Length);
        }
        /// <summary>
        /// Returns symbols for the locals emitted in the original method,
        /// based on the local signatures from the IL and the names and
        /// slots from the PDB. The actual locals are needed to ensure the
        /// local slots in the generated method match the original.
        /// </summary>
        private static void GetLocals(
            ArrayBuilder<LocalSymbol> builder,
            MethodSymbol method,
            ImmutableArray<string> names,
            ImmutableArray<LocalInfo<TypeSymbol>> localInfo,
            ImmutableDictionary<int, ImmutableArray<bool>> dynamicLocalMap,
            SourceAssemblySymbol containingAssembly)
        {
            if (localInfo.Length == 0)
            {
                // When debugging a .dmp without a heap, localInfo will be empty although
                // names may be non-empty if there is a PDB. Since there's no type info, the
                // locals are dropped. Note this means the local signature of any generated
                // method will not match the original signature, so new locals will overlap
                // original locals. That is ok since there is no live process for the debugger
                // to update (any modified values exist in the debugger only).
                return;
            }

            Debug.Assert(localInfo.Length >= names.Length);

            for (int i = 0; i < localInfo.Length; i++)
            {
                var name = (i < names.Length) ? names[i] : null;
                var info = localInfo[i];
                var isPinned = info.IsPinned;

                LocalDeclarationKind kind;
                RefKind refKind;
                TypeSymbol type;
                if (info.IsByRef && isPinned)
                {
                    kind = LocalDeclarationKind.FixedVariable;
                    refKind = RefKind.None;
                    type = new PointerTypeSymbol(info.Type);
                }
                else
                {
                    kind = LocalDeclarationKind.RegularVariable;
                    refKind = info.IsByRef ? RefKind.Ref : RefKind.None;
                    type = info.Type;
                }

                ImmutableArray<bool> dynamicFlags;
                if (dynamicLocalMap != null && dynamicLocalMap.TryGetValue(i, out dynamicFlags))
                {
                    type = DynamicTypeDecoder.TransformTypeWithoutCustomModifierFlags(
                        type,
                        containingAssembly,
                        refKind,
                        dynamicFlags);
                }

                // Custom modifiers can be dropped since binding ignores custom
                // modifiers from locals and since we only need to preserve
                // the type of the original local in the generated method.
                builder.Add(new EELocalSymbol(method, EELocalSymbol.NoLocations, name, i, kind, type, refKind, isPinned, isCompilerGenerated: false, canScheduleToStack: false));
            }
        }
        internal sealed override TypeSymbol GetFieldType(ConsList <FieldSymbol> fieldsBeingBound)
        {
            Debug.Assert(fieldsBeingBound != null);

            if ((object)_lazyType != null)
            {
                return(_lazyType);
            }

            var declarator  = VariableDeclaratorNode;
            var fieldSyntax = GetFieldDeclaration(declarator);
            var typeSyntax  = fieldSyntax.Declaration.Type;

            var compilation = this.DeclaringCompilation;

            var        diagnostics = DiagnosticBag.GetInstance();
            TypeSymbol type;

            // When we have multiple declarators, we report the type diagnostics on only the first.
            DiagnosticBag diagnosticsForFirstDeclarator = DiagnosticBag.GetInstance();

            Symbol associatedPropertyOrEvent = this.AssociatedSymbol;

            if ((object)associatedPropertyOrEvent != null && associatedPropertyOrEvent.Kind == SymbolKind.Event)
            {
                EventSymbol @event = (EventSymbol)associatedPropertyOrEvent;
                if (@event.IsWindowsRuntimeEvent)
                {
                    NamedTypeSymbol tokenTableType = this.DeclaringCompilation.GetWellKnownType(WellKnownType.System_Runtime_InteropServices_WindowsRuntime_EventRegistrationTokenTable_T);
                    Binder.ReportUseSiteDiagnostics(tokenTableType, diagnosticsForFirstDeclarator, this.ErrorLocation);

                    // CONSIDER: Do we want to guard against the possibility that someone has created their own EventRegistrationTokenTable<T>
                    // type that has additional generic constraints?
                    type = tokenTableType.Construct(@event.Type);
                }
                else
                {
                    type = @event.Type;
                }
            }
            else
            {
                var binderFactory = compilation.GetBinderFactory(SyntaxTree);
                var binder        = binderFactory.GetBinder(typeSyntax);

                binder = binder.WithContainingMemberOrLambda(this);
                if (!ContainingType.IsScriptClass)
                {
                    type = binder.BindType(typeSyntax, diagnosticsForFirstDeclarator);
                    if (IsFixed)
                    {
                        type = new PointerTypeSymbol(type);
                    }
                }
                else
                {
                    bool isVar;
                    type = binder.BindType(typeSyntax, diagnostics, out isVar);

                    Debug.Assert((object)type != null || isVar);

                    if (isVar)
                    {
                        if (this.IsConst)
                        {
                            diagnosticsForFirstDeclarator.Add(ErrorCode.ERR_ImplicitlyTypedVariableCannotBeConst, typeSyntax.Location);
                        }

                        if (fieldsBeingBound.ContainsReference(this))
                        {
                            diagnostics.Add(ErrorCode.ERR_RecursivelyTypedVariable, this.ErrorLocation, this);
                            type = null;
                        }
                        else if (fieldSyntax.Declaration.Variables.Count > 1)
                        {
                            diagnosticsForFirstDeclarator.Add(ErrorCode.ERR_ImplicitlyTypedVariableMultipleDeclarator, typeSyntax.Location);
                        }
                        else
                        {
                            fieldsBeingBound = new ConsList <FieldSymbol>(this, fieldsBeingBound);

                            var initializerBinder = new ImplicitlyTypedFieldBinder(binder, fieldsBeingBound);
                            var initializerOpt    = initializerBinder.BindInferredVariableInitializer(diagnostics, RefKind.None, (EqualsValueClauseSyntax)declarator.Initializer, declarator);

                            if (initializerOpt != null)
                            {
                                if ((object)initializerOpt.Type != null && !initializerOpt.Type.IsErrorType())
                                {
                                    type = initializerOpt.Type;
                                }

                                _lazyFieldTypeInferred = 1;
                            }
                        }

                        if ((object)type == null)
                        {
                            type = binder.CreateErrorType("var");
                        }
                    }
                }

                if (IsFixed)
                {
                    if (ContainingType.TypeKind != TypeKind.Struct)
                    {
                        diagnostics.Add(ErrorCode.ERR_FixedNotInStruct, ErrorLocation);
                    }

                    var elementType = ((PointerTypeSymbol)type).PointedAtType;
                    int elementSize = elementType.FixedBufferElementSizeInBytes();
                    if (elementSize == 0)
                    {
                        var loc = typeSyntax.Location;
                        diagnostics.Add(ErrorCode.ERR_IllegalFixedType, loc);
                    }

                    if (!binder.InUnsafeRegion)
                    {
                        diagnosticsForFirstDeclarator.Add(ErrorCode.ERR_UnsafeNeeded, declarator.Location);
                    }
                }
            }

            // update the lazyType only if it contains value last seen by the current thread:
            if ((object)Interlocked.CompareExchange(ref _lazyType, type, null) == null)
            {
                TypeChecks(type, fieldSyntax, diagnostics);

                // CONSIDER: SourceEventFieldSymbol would like to suppress these diagnostics.
                compilation.DeclarationDiagnostics.AddRange(diagnostics);

                bool isFirstDeclarator = fieldSyntax.Declaration.Variables[0] == declarator;
                if (isFirstDeclarator)
                {
                    compilation.DeclarationDiagnostics.AddRange(diagnosticsForFirstDeclarator);
                }

                state.NotePartComplete(CompletionPart.Type);
            }

            diagnostics.Free();
            diagnosticsForFirstDeclarator.Free();
            return(_lazyType);
        }
Example #10
0
        private PointerTypeSymbol SubstitutePointerType(PointerTypeSymbol t)
        {
            var oldPointedAtType = new TypeWithModifiers(t.PointedAtType, t.CustomModifiers);
            TypeWithModifiers pointedAtType = oldPointedAtType.SubstituteType(this);
            if (pointedAtType == oldPointedAtType)
            {
                return t;
            }

            return new PointerTypeSymbol(pointedAtType.Type, pointedAtType.CustomModifiers);
        }
Example #11
0
        private PointerTypeSymbol SubstitutePointerType(PointerTypeSymbol t)
        {
            TypeSymbol pointedAtType = SubstituteType(t.PointedAtType);
            if (ReferenceEquals(pointedAtType, t.PointedAtType))
            {
                return t;
            }

            return new PointerTypeSymbol(pointedAtType, t.CustomModifiers);
        }
Example #12
0
 internal bool Equals(PointerTypeSymbol other)
 {
     return(this.Equals(other, TypeCompareKind.IgnoreTupleNames));
 }
Example #13
0
 internal bool Equals(PointerTypeSymbol other)
 {
     return(this.Equals(other, false, false));
 }
Example #14
0
        public void TestPointerTypeTransforms()
        {
            CommonTestInitialization();

            // public unsafe class UnsafeClass<T> : Base2<int*[], Outer<dynamic>.Inner<Outer<dynamic>.Inner<T[], dynamic>.InnerInner<int*[][]>[], dynamic>.InnerInner<dynamic>[][]> { }
            var unsafeClass = _assembly.Modules[0].GlobalNamespace.GetMember<NamedTypeSymbol>("UnsafeClass");
            Assert.False(unsafeClass.ContainsDynamic());
            Assert.True(unsafeClass.BaseType.ContainsDynamic());

            var unsafeClassTypeParam = unsafeClass.TypeParameters[0];
            // T[]
            var arrayOfDerivedTypeParam = ArrayTypeSymbol.CreateCSharpArray(_assembly, unsafeClassTypeParam, ImmutableArray.Create<CustomModifier>(), 1);
            // Outer<dynamic>
            var outerClassOfDynamic = _outerClass.Construct(s_dynamicType);
            // Outer<dynamic>.Inner<T[], dynamic>
            var complicatedInner = outerClassOfDynamic.GetTypeMember("Inner").Construct(arrayOfDerivedTypeParam, s_dynamicType);
            // int*[]
            var pointerToInt = new PointerTypeSymbol(_intType, ImmutableArray.Create<CustomModifier>());
            var arrayOfPointerToInt = ArrayTypeSymbol.CreateCSharpArray(_assembly, pointerToInt, ImmutableArray.Create<CustomModifier>(), 1);
            // int*[][]
            var arrayOfArrayOfPointerToInt = ArrayTypeSymbol.CreateCSharpArray(_assembly, arrayOfPointerToInt, ImmutableArray.Create<CustomModifier>(), 1);
            // Outer<dynamic>.Inner<T[], dynamic>.InnerInner<int*[][]>
            var complicatedInnerInner = complicatedInner.GetTypeMember("InnerInner").Construct(arrayOfArrayOfPointerToInt);
            // Outer<dynamic>.Inner<T[], dynamic>.InnerInner<int*[][]>[]
            var complicatedInnerInnerArray = ArrayTypeSymbol.CreateCSharpArray(_assembly, complicatedInnerInner, ImmutableArray.Create<CustomModifier>(), 1);
            // Outer<dynamic>.Inner<Outer<dynamic>.Inner<T[], dynamic>.InnerInner<int*[][]>[], dynamic>
            complicatedInner = outerClassOfDynamic.GetTypeMember("Inner").Construct(complicatedInnerInnerArray, s_dynamicType);
            // Outer<dynamic>.Inner<Outer<dynamic>.Inner<T[], dynamic>.InnerInner<int*[][]>[], dynamic>.InnerInner<dynamic>
            complicatedInnerInner = complicatedInner.GetTypeMember("InnerInner").Construct(s_dynamicType);
            // Outer<dynamic>.Inner<Outer<dynamic>.Inner<T[], dynamic>.InnerInner<int*[][]>[], dynamic>.InnerInner<dynamic>[][]
            complicatedInnerInnerArray = ArrayTypeSymbol.CreateCSharpArray(_assembly, complicatedInnerInner, ImmutableArray.Create<CustomModifier>(), 1);
            var complicatedInnerInnerArrayOfArray = ArrayTypeSymbol.CreateCSharpArray(_assembly, complicatedInnerInnerArray, ImmutableArray.Create<CustomModifier>(), 1);
            // Base2<int*[], Outer<dynamic>.Inner<Outer<dynamic>.Inner<T[], dynamic>.InnerInner<int*[][]>[], dynamic>.InnerInner<dynamic>[][]>
            var baseType = _base2Class.Construct(arrayOfPointerToInt, complicatedInnerInnerArrayOfArray);

            Assert.Equal(baseType, unsafeClass.BaseType);
        }
        public void TypeMap()
        {
            var source = @"
struct S<T> where T : struct
{
}
";

            var comp = CreateCompilationWithMscorlib(source);
            comp.VerifyDiagnostics();

            var intType = comp.GetSpecialType(SpecialType.System_Int32);
            var customModifiers = ImmutableArray.Create(CSharpCustomModifier.CreateOptional(intType));

            var structType = comp.GlobalNamespace.GetMember<NamedTypeSymbol>("S");
            var typeParamType = structType.TypeParameters.Single();

            var pointerType = new PointerTypeSymbol(typeParamType, customModifiers); // NOTE: We're constructing this manually, since it's illegal.
            var arrayType = new ArrayTypeSymbol(comp.Assembly, typeParamType, customModifiers); // This is legal, but we're already manually constructing types.

            var typeMap = new TypeMap(ImmutableArray.Create(typeParamType), ImmutableArray.Create<TypeSymbol>(intType));

            var substitutedPointerType = (PointerTypeSymbol)typeMap.SubstituteType(pointerType);
            var substitutedArrayType = (ArrayTypeSymbol)typeMap.SubstituteType(arrayType);

            // The map changed the types.
            Assert.Equal(intType, substitutedPointerType.PointedAtType);
            Assert.Equal(intType, substitutedArrayType.ElementType);

            // The map preserved the custom modifiers.
            Assert.Equal(customModifiers, substitutedPointerType.CustomModifiers);
            Assert.Equal(customModifiers, substitutedArrayType.CustomModifiers);
        }
Example #16
0
        // Based on ExpressionBinder::bindPtrAddr.
        private BoundExpression BindAddressOfExpression(PrefixUnaryExpressionSyntax node, DiagnosticBag diagnostics)
        {
            BoundExpression operand = BindValue(node.Operand, diagnostics, BindValueKind.AddressOf);

            bool hasErrors = operand.HasAnyErrors; // This would propagate automatically, but by reading it explicitly we can reduce cascading.
            bool isFixedStatementAddressOfExpression = SyntaxFacts.IsFixedStatementExpression(node);

            switch (operand.Kind)
            {
                case BoundKind.MethodGroup:
                case BoundKind.Lambda:
                case BoundKind.UnboundLambda:
                    {
                        Debug.Assert(hasErrors);
                        return new BoundAddressOfOperator(node, operand, isFixedStatementAddressOfExpression, CreateErrorType(), hasErrors: true);
                    }
            }

            TypeSymbol operandType = operand.Type;
            Debug.Assert((object)operandType != null || hasErrors, "BindValue should have caught a null operand type");

            bool isManagedType = operandType.IsManagedType;
            bool allowManagedAddressOf = Flags.Includes(BinderFlags.AllowManagedAddressOf);
            if (!allowManagedAddressOf)
            {
                if (!hasErrors && isManagedType)
                {
                    hasErrors = true;
                    Error(diagnostics, ErrorCode.ERR_ManagedAddr, node, operandType);
                }

                if (!hasErrors)
                {
                    Symbol accessedLocalOrParameterOpt;
                    if (IsNonMoveableVariable(operand, out accessedLocalOrParameterOpt) == isFixedStatementAddressOfExpression)
                    {
                        Error(diagnostics, isFixedStatementAddressOfExpression ? ErrorCode.ERR_FixedNotNeeded : ErrorCode.ERR_FixedNeeded, node);
                        hasErrors = true;
                    }
                }
            }

            TypeSymbol pointerType = new PointerTypeSymbol(isManagedType && allowManagedAddressOf
                ? GetSpecialType(SpecialType.System_IntPtr, diagnostics, node)
                : operandType ?? CreateErrorType());
            return new BoundAddressOfOperator(node, operand, isFixedStatementAddressOfExpression, pointerType, hasErrors);
        }
Example #17
0
        /// <summary>
        /// Wrap the initializer in a BoundFixedLocalCollectionInitializer so that the rewriter will have the
        /// information it needs (e.g. conversions, helper methods).
        /// </summary>
        private BoundExpression GetFixedLocalCollectionInitializer(BoundExpression initializer, TypeSymbol elementType, TypeSymbol declType, bool hasErrors, DiagnosticBag diagnostics)
        {
            Debug.Assert(initializer != null);

            CSharpSyntaxNode initializerSyntax = initializer.Syntax;

            TypeSymbol pointerType = new PointerTypeSymbol(elementType);
            HashSet<DiagnosticInfo> useSiteDiagnostics = null;
            Conversion elementConversion = this.Conversions.ClassifyConversion(pointerType, declType, ref useSiteDiagnostics);
            diagnostics.Add(initializerSyntax, useSiteDiagnostics);

            if (!elementConversion.IsValid || !elementConversion.IsImplicit)
            {
                GenerateImplicitConversionError(diagnostics, this.Compilation, initializerSyntax, elementConversion, pointerType, declType);
                hasErrors = true;
            }

            return new BoundFixedLocalCollectionInitializer(
                initializerSyntax,
                pointerType,
                elementConversion,
                initializer,
                initializer.Type,
                hasErrors);
        }
Example #18
0
        public void PointerMemberAccessSemanticModelAPIs()
        {
            var text = @"
unsafe class C
{
    void M()
    {
        S s;
        S* p = &s;
        p->M();
    }
}

struct S
{
    public void M() { }
    public void M(int x) { }
}
";
            var compilation = CreateCompilationWithMscorlib(text, options: TestOptions.UnsafeReleaseDll);
            var tree = compilation.SyntaxTrees.Single();
            var model = compilation.GetSemanticModel(tree);

            var syntax = tree.GetCompilationUnitRoot().DescendantNodes().OfType<MemberAccessExpressionSyntax>().Single();
            Assert.Equal(SyntaxKind.PointerMemberAccessExpression, syntax.Kind());

            var receiverSyntax = syntax.Expression;
            var methodGroupSyntax = syntax;
            var callSyntax = syntax.Parent;

            var structType = compilation.GlobalNamespace.GetMember<TypeSymbol>("S");
            var structPointerType = new PointerTypeSymbol(structType);
            var structMethod1 = structType.GetMembers("M").OfType<MethodSymbol>().Single(m => m.ParameterCount == 0);
            var structMethod2 = structType.GetMembers("M").OfType<MethodSymbol>().Single(m => m.ParameterCount == 1);

            var receiverSummary = model.GetSemanticInfoSummary(receiverSyntax);
            var receiverSymbol = receiverSummary.Symbol;
            Assert.Equal(SymbolKind.Local, receiverSymbol.Kind);
            Assert.Equal(structPointerType, ((LocalSymbol)receiverSymbol).Type);
            Assert.Equal("p", receiverSymbol.Name);
            Assert.Equal(CandidateReason.None, receiverSummary.CandidateReason);
            Assert.Equal(0, receiverSummary.CandidateSymbols.Length);
            Assert.Equal(structPointerType, receiverSummary.Type);
            Assert.Equal(structPointerType, receiverSummary.ConvertedType);
            Assert.Equal(ConversionKind.Identity, receiverSummary.ImplicitConversion.Kind);
            Assert.Equal(0, receiverSummary.MethodGroup.Length);

            var methodGroupSummary = model.GetSemanticInfoSummary(methodGroupSyntax);
            Assert.Equal(structMethod1, methodGroupSummary.Symbol);
            Assert.Equal(CandidateReason.None, methodGroupSummary.CandidateReason);
            Assert.Equal(0, methodGroupSummary.CandidateSymbols.Length);
            Assert.Null(methodGroupSummary.Type);
            Assert.Null(methodGroupSummary.ConvertedType);
            Assert.Equal(ConversionKind.Identity, methodGroupSummary.ImplicitConversion.Kind);
            Assert.True(methodGroupSummary.MethodGroup.SetEquals(ImmutableArray.Create<IMethodSymbol>(structMethod1, structMethod2), EqualityComparer<IMethodSymbol>.Default));

            var callSummary = model.GetSemanticInfoSummary(callSyntax);
            Assert.Equal(structMethod1, callSummary.Symbol);
            Assert.Equal(CandidateReason.None, callSummary.CandidateReason);
            Assert.Equal(0, callSummary.CandidateSymbols.Length);
            Assert.Equal(SpecialType.System_Void, callSummary.Type.SpecialType);
            Assert.Equal(SpecialType.System_Void, callSummary.ConvertedType.SpecialType);
            Assert.Equal(ConversionKind.Identity, callSummary.ImplicitConversion.Kind);
            Assert.Equal(0, callSummary.MethodGroup.Length);
        }
 public virtual void VisitPointerType(PointerTypeSymbol symbol)
 {
     DefaultVisit(symbol);
 }
Example #20
0
        public void FixedSemanticModelSymbolInfo()
        {
            var text = @"
using System;

unsafe class C
{
    char c = 'a';
    char[] a = new char[1];

    static void Main()
    {
        C c = new C();
        fixed (char* p = &c.c, q = c.a, r = ""hello"")
        {
            Console.WriteLine(*p);
            Console.WriteLine(*q);
            Console.WriteLine(*r);
        }
    }
}
";
            var compilation = CreateCompilationWithMscorlib(text, options: TestOptions.UnsafeReleaseDll);
            var tree = compilation.SyntaxTrees.Single();
            var model = compilation.GetSemanticModel(tree);

            var stringSymbol = compilation.GetSpecialType(SpecialType.System_String);
            var charSymbol = compilation.GetSpecialType(SpecialType.System_Char);
            var charPointerSymbol = new PointerTypeSymbol(charSymbol);

            const int numSymbols = 3;
            var declarators = tree.GetCompilationUnitRoot().DescendantNodes().OfType<VariableDeclaratorSyntax>().Reverse().Take(numSymbols).Reverse().ToArray();
            var dereferences = tree.GetCompilationUnitRoot().DescendantNodes().Where(syntax => syntax.IsKind(SyntaxKind.PointerIndirectionExpression)).ToArray();
            Assert.Equal(numSymbols, dereferences.Length);

            var declaredSymbols = declarators.Select(syntax => (LocalSymbol)model.GetDeclaredSymbol(syntax)).ToArray();

            var initializerSummaries = declarators.Select(syntax => model.GetSemanticInfoSummary(syntax.Initializer.Value)).ToArray();

            for (int i = 0; i < numSymbols; i++)
            {
                var summary = initializerSummaries[i];
                Assert.Equal(0, summary.CandidateSymbols.Length);
                Assert.Equal(CandidateReason.None, summary.CandidateReason);
                Assert.Equal(summary.Type, summary.ConvertedType);
                Assert.Equal(Conversion.Identity, summary.ImplicitConversion);
                Assert.Equal(0, summary.MethodGroup.Length);
                Assert.Null(summary.Alias);
            }

            var summary0 = initializerSummaries[0];
            Assert.Null(summary0.Symbol);
            Assert.Equal(charPointerSymbol, summary0.Type);

            var summary1 = initializerSummaries[1];
            var arraySymbol = compilation.GlobalNamespace.GetMember<TypeSymbol>("C").GetMember<FieldSymbol>("a");
            Assert.Equal(arraySymbol, summary1.Symbol);
            Assert.Equal(arraySymbol.Type, summary1.Type);

            var summary2 = initializerSummaries[2];
            Assert.Null(summary2.Symbol);
            Assert.Equal(stringSymbol, summary2.Type);

            var accessSymbolInfos = dereferences.Select(syntax => model.GetSymbolInfo(((PrefixUnaryExpressionSyntax)syntax).Operand)).ToArray();

            for (int i = 0; i < numSymbols; i++)
            {
                SymbolInfo info = accessSymbolInfos[i];
                Assert.Equal(declaredSymbols[i], info.Symbol);
                Assert.Equal(0, info.CandidateSymbols.Length);
                Assert.Equal(CandidateReason.None, info.CandidateReason);
            }
        }
        private void GetPointerArithmeticOperators(
            BinaryOperatorKind kind,
            PointerTypeSymbol pointerType,
            ArrayBuilder<BinaryOperatorSignature> operators)
        {
            Debug.Assert((object)pointerType != null);
            AssertNotChecked(kind);

            switch (kind)
            {
                case BinaryOperatorKind.Addition:
                    operators.Add(new BinaryOperatorSignature(BinaryOperatorKind.PointerAndIntAddition, pointerType, Compilation.GetSpecialType(SpecialType.System_Int32), pointerType));
                    operators.Add(new BinaryOperatorSignature(BinaryOperatorKind.PointerAndUIntAddition, pointerType, Compilation.GetSpecialType(SpecialType.System_UInt32), pointerType));
                    operators.Add(new BinaryOperatorSignature(BinaryOperatorKind.PointerAndLongAddition, pointerType, Compilation.GetSpecialType(SpecialType.System_Int64), pointerType));
                    operators.Add(new BinaryOperatorSignature(BinaryOperatorKind.PointerAndULongAddition, pointerType, Compilation.GetSpecialType(SpecialType.System_UInt64), pointerType));
                    operators.Add(new BinaryOperatorSignature(BinaryOperatorKind.IntAndPointerAddition, Compilation.GetSpecialType(SpecialType.System_Int32), pointerType, pointerType));
                    operators.Add(new BinaryOperatorSignature(BinaryOperatorKind.UIntAndPointerAddition, Compilation.GetSpecialType(SpecialType.System_UInt32), pointerType, pointerType));
                    operators.Add(new BinaryOperatorSignature(BinaryOperatorKind.LongAndPointerAddition, Compilation.GetSpecialType(SpecialType.System_Int64), pointerType, pointerType));
                    operators.Add(new BinaryOperatorSignature(BinaryOperatorKind.ULongAndPointerAddition, Compilation.GetSpecialType(SpecialType.System_UInt64), pointerType, pointerType));
                    break;
                case BinaryOperatorKind.Subtraction:
                    operators.Add(new BinaryOperatorSignature(BinaryOperatorKind.PointerAndIntSubtraction, pointerType, Compilation.GetSpecialType(SpecialType.System_Int32), pointerType));
                    operators.Add(new BinaryOperatorSignature(BinaryOperatorKind.PointerAndUIntSubtraction, pointerType, Compilation.GetSpecialType(SpecialType.System_UInt32), pointerType));
                    operators.Add(new BinaryOperatorSignature(BinaryOperatorKind.PointerAndLongSubtraction, pointerType, Compilation.GetSpecialType(SpecialType.System_Int64), pointerType));
                    operators.Add(new BinaryOperatorSignature(BinaryOperatorKind.PointerAndULongSubtraction, pointerType, Compilation.GetSpecialType(SpecialType.System_UInt64), pointerType));
                    operators.Add(new BinaryOperatorSignature(BinaryOperatorKind.PointerSubtraction, pointerType, pointerType, Compilation.GetSpecialType(SpecialType.System_Int64)));
                    break;
            }
        }
        /// <summary>
        /// This rather confusing method tries to reproduce the functionality of ExpressionBinder::bindPtrAddMul and
        /// ExpressionBinder::bindPtrMul.  The basic idea is that we have a numeric expression, x, and a pointer type, 
        /// T*, and we want to multiply x by sizeof(T).  Unfortunately, we need to stick in some conversions to make
        /// everything work.
        /// 
        ///   1) If x is an int, then convert it to an IntPtr (i.e. a native int).  Dev10 offers no explanation (ExpressionBinder::bindPtrMul).
        ///   2) Do overload resolution based on the (possibly converted) type of X and int (the type of sizeof(T)).
        ///   3) If the result type of the chosen multiplication operator is signed, convert the product to IntPtr;
        ///      otherwise, convert the product to UIntPtr.
        /// </summary>
        private BoundExpression MakeSizeOfMultiplication(BoundExpression numericOperand, PointerTypeSymbol pointerType, bool isChecked)
        {
            var sizeOfExpression = _factory.Sizeof(pointerType.PointedAtType);
            Debug.Assert(sizeOfExpression.Type.SpecialType == SpecialType.System_Int32);

            // Common case: adding or subtracting one  (e.g. for ++)
            if (numericOperand.ConstantValue?.UInt64Value == 1)
            {
                // We could convert this to a native int (as the unoptimized multiplication would be),
                // but that would be a no-op (int to native int), so don't bother.
                return sizeOfExpression;
            }

            var numericSpecialType = numericOperand.Type.SpecialType;

            // Optimization: the size is exactly one byte, then multiplication is unnecessary.
            if (sizeOfExpression.ConstantValue?.Int32Value == 1)
            {
                // As in ExpressionBinder::bindPtrAddMul, we apply the following conversions:
                //   int -> int (add allows int32 operands and will extend to native int if necessary)
                //   uint -> native uint (add will sign-extend 32bit operand on 64bit, we do not want that happening)
                //   long -> native int
                //   ulong -> native uint
                // Note that these are not the types we would see if we let the multiplication happen.
                // ACASEY: These rules are inferred from the native compiler.

                SpecialType destinationType = numericSpecialType;
                switch (numericSpecialType)
                {
                    case SpecialType.System_Int32:
                        // add operator can take int32 and extend to 64bit if necessary
                        break;
                    case SpecialType.System_UInt32:
                        // add operator treats operands as signed and will sign-extend on x64
                        // to prevent sign-extending, convert the operand to unsigned native int.
                        var constVal = numericOperand.ConstantValue;
                        if (constVal == null || constVal.UInt32Value > int.MaxValue)
                        {
                            destinationType = SpecialType.System_UIntPtr;
                        }
                        break;
                    case SpecialType.System_Int64:
                        destinationType = SpecialType.System_IntPtr;
                        break;
                    case SpecialType.System_UInt64:
                        destinationType = SpecialType.System_UIntPtr;
                        break;
                    default:
                        throw ExceptionUtilities.UnexpectedValue(numericSpecialType);
                }

                return destinationType == numericSpecialType
                    ? numericOperand
                    : _factory.Convert(_factory.SpecialType(destinationType), numericOperand, Conversion.IntegerToPointer);
            }

            BinaryOperatorKind multiplicationKind = BinaryOperatorKind.Multiplication;

            TypeSymbol multiplicationResultType;
            TypeSymbol convertedMultiplicationResultType;
            switch (numericSpecialType)
            {
                case SpecialType.System_Int32:
                    {
                        TypeSymbol nativeIntType = _factory.SpecialType(SpecialType.System_IntPtr);

                        // From ExpressionBinder::bindPtrMul:
                        // this multiplication needs to be done as natural ints, but since a (int * natint) ==> natint,
                        // we only need to promote one side

                        numericOperand = _factory.Convert(nativeIntType, numericOperand, Conversion.IntegerToPointer, isChecked);
                        multiplicationKind |= BinaryOperatorKind.Int; //i.e. signed
                        multiplicationResultType = nativeIntType;
                        convertedMultiplicationResultType = nativeIntType;
                        break;
                    }
                case SpecialType.System_UInt32:
                    {
                        TypeSymbol longType = _factory.SpecialType(SpecialType.System_Int64);
                        TypeSymbol nativeIntType = _factory.SpecialType(SpecialType.System_IntPtr);

                        // We're multiplying a uint by an int, so promote both to long (same as normal operator overload resolution).
                        numericOperand = _factory.Convert(longType, numericOperand, Conversion.ExplicitNumeric, isChecked);
                        sizeOfExpression = _factory.Convert(longType, sizeOfExpression, Conversion.ExplicitNumeric, isChecked);
                        multiplicationKind |= BinaryOperatorKind.Long;
                        multiplicationResultType = longType;
                        convertedMultiplicationResultType = nativeIntType;
                        break;
                    }
                case SpecialType.System_Int64:
                    {
                        TypeSymbol longType = _factory.SpecialType(SpecialType.System_Int64);
                        TypeSymbol nativeIntType = _factory.SpecialType(SpecialType.System_IntPtr);

                        // We're multiplying a long by an int, so promote the int to long (same as normal operator overload resolution).
                        sizeOfExpression = _factory.Convert(longType, sizeOfExpression, Conversion.ExplicitNumeric, isChecked);
                        multiplicationKind |= BinaryOperatorKind.Long;
                        multiplicationResultType = longType;
                        convertedMultiplicationResultType = nativeIntType;
                        break;
                    }
                case SpecialType.System_UInt64:
                    {
                        TypeSymbol ulongType = _factory.SpecialType(SpecialType.System_UInt64);
                        TypeSymbol nativeUIntType = _factory.SpecialType(SpecialType.System_UIntPtr);

                        // We're multiplying a ulong by an int, so promote the int to ulong (same as normal operator overload resolution).
                        sizeOfExpression = _factory.Convert(ulongType, sizeOfExpression, Conversion.ExplicitNumeric, isChecked);
                        multiplicationKind |= BinaryOperatorKind.ULong;
                        multiplicationResultType = ulongType;
                        convertedMultiplicationResultType = nativeUIntType; //unsigned since multiplicationResultType is unsigned
                        break;
                    }
                default:
                    {
                        throw ExceptionUtilities.UnexpectedValue(numericSpecialType);
                    }
            }

            if (isChecked)
            {
                multiplicationKind |= BinaryOperatorKind.Checked;
            }
            var multiplication = _factory.Binary(multiplicationKind, multiplicationResultType, numericOperand, sizeOfExpression);
            return convertedMultiplicationResultType == multiplicationResultType
                ? multiplication
                : _factory.Convert(convertedMultiplicationResultType, multiplication, Conversion.IntegerToPointer); // NOTE: for some reason, dev10 doesn't check this conversion.
        }
        private PointerTypeSymbol TransformPointerType(PointerTypeSymbol pointerType)
        {
            Debug.Assert(!dynamicTransformFlags[index]);

            index++;
            if (!HandleCustomModifiers(pointerType.CustomModifiers.Length))
            {
                return null;
            }

            TypeSymbol transformedPointedAtType = TransformType(pointerType.PointedAtType);
            if ((object)transformedPointedAtType == null)
            {
                return null;
            }

            return transformedPointedAtType == pointerType.PointedAtType ?
                pointerType :
                new PointerTypeSymbol(transformedPointedAtType, pointerType.CustomModifiers);
        }