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()); }
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; }
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; } }
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); }
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); }
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); }
private PointerTypeSymbol SubstitutePointerType(PointerTypeSymbol t) { TypeSymbol pointedAtType = SubstituteType(t.PointedAtType); if (ReferenceEquals(pointedAtType, t.PointedAtType)) { return t; } return new PointerTypeSymbol(pointedAtType, t.CustomModifiers); }
internal bool Equals(PointerTypeSymbol other) { return(this.Equals(other, TypeCompareKind.IgnoreTupleNames)); }
internal bool Equals(PointerTypeSymbol other) { return(this.Equals(other, false, false)); }
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); }
// 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); }
/// <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); }
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); }
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); }