public StateMachineFieldSymbol(NamedTypeSymbol stateMachineType, TypeSymbol type, string name, LocalSlotDebugInfo slotDebugInfo, int slotIndex, bool isPublic) : this(stateMachineType, TypeWithAnnotations.Create(type), name, slotDebugInfo, slotIndex, isPublic) { }
public override BoundNode VisitTryStatement(BoundTryStatement node) { var tryStatementSyntax = node.Syntax; // If you add a syntax kind to the assertion below, please also ensure // that the scenario has been tested with Edit-and-Continue. Debug.Assert( tryStatementSyntax.IsKind(SyntaxKind.TryStatement) || tryStatementSyntax.IsKind(SyntaxKind.UsingStatement) || tryStatementSyntax.IsKind(SyntaxKind.ForEachStatement) || tryStatementSyntax.IsKind(SyntaxKind.ForEachVariableStatement) || tryStatementSyntax.IsKind(SyntaxKind.LocalDeclarationStatement) || tryStatementSyntax.IsKind(SyntaxKind.LockStatement)); BoundStatement finalizedRegion; BoundBlock rewrittenFinally; var finallyContainsAwaits = _analysis.FinallyContainsAwaits(node); if (!finallyContainsAwaits) { finalizedRegion = RewriteFinalizedRegion(node); rewrittenFinally = (BoundBlock)this.Visit(node.FinallyBlockOpt); if (rewrittenFinally == null) { return(finalizedRegion); } var asTry = finalizedRegion as BoundTryStatement; if (asTry != null) { // since finalized region is a try we can just attach finally to it Debug.Assert(asTry.FinallyBlockOpt == null); return(asTry.Update(asTry.TryBlock, asTry.CatchBlocks, rewrittenFinally, asTry.FinallyLabelOpt, asTry.PreferFaultHandler)); } else { // wrap finalizedRegion into a Try with a finally. return(_F.Try((BoundBlock)finalizedRegion, ImmutableArray <BoundCatchBlock> .Empty, rewrittenFinally)); } } // rewrite finalized region (try and catches) in the current frame var frame = PushFrame(node); finalizedRegion = RewriteFinalizedRegion(node); rewrittenFinally = (BoundBlock)this.VisitBlock(node.FinallyBlockOpt); PopFrame(); var exceptionType = _F.SpecialType(SpecialType.System_Object); var pendingExceptionLocal = new SynthesizedLocal(_F.CurrentFunction, TypeWithAnnotations.Create(exceptionType), SynthesizedLocalKind.TryAwaitPendingException, tryStatementSyntax); var finallyLabel = _F.GenerateLabel("finallyLabel"); var pendingBranchVar = new SynthesizedLocal(_F.CurrentFunction, TypeWithAnnotations.Create(_F.SpecialType(SpecialType.System_Int32)), SynthesizedLocalKind.TryAwaitPendingBranch, tryStatementSyntax); var catchAll = _F.Catch(_F.Local(pendingExceptionLocal), _F.Block()); var catchAndPendException = _F.Try( _F.Block( finalizedRegion, _F.HiddenSequencePoint(), _F.Goto(finallyLabel), PendBranches(frame, pendingBranchVar, finallyLabel)), ImmutableArray.Create(catchAll), finallyLabel: finallyLabel); BoundBlock syntheticFinallyBlock = _F.Block( _F.HiddenSequencePoint(), _F.Label(finallyLabel), rewrittenFinally, _F.HiddenSequencePoint(), UnpendException(pendingExceptionLocal), UnpendBranches( frame, pendingBranchVar, pendingExceptionLocal)); BoundStatement syntheticFinally = syntheticFinallyBlock; if (_F.CurrentFunction.IsAsync && _F.CurrentFunction.IsIterator) { // We wrap this block so that it can be processed as a finally block by async-iterator rewriting syntheticFinally = _F.ExtractedFinallyBlock(syntheticFinallyBlock); } var locals = ArrayBuilder <LocalSymbol> .GetInstance(); var statements = ArrayBuilder <BoundStatement> .GetInstance(); statements.Add(_F.HiddenSequencePoint()); locals.Add(pendingExceptionLocal); statements.Add(_F.Assignment(_F.Local(pendingExceptionLocal), _F.Default(pendingExceptionLocal.Type))); locals.Add(pendingBranchVar); statements.Add(_F.Assignment(_F.Local(pendingBranchVar), _F.Default(pendingBranchVar.Type))); LocalSymbol returnLocal = frame.returnValue; if (returnLocal != null) { locals.Add(returnLocal); } statements.Add(catchAndPendException); statements.Add(syntheticFinally); var completeTry = _F.Block( locals.ToImmutableAndFree(), statements.ToImmutableAndFree()); return(completeTry); }
internal static BoundBlock ConstructFieldLikeEventAccessorBody_Regular(SourceEventSymbol eventSymbol, bool isAddMethod, CSharpCompilation compilation, BindingDiagnosticBag diagnostics) { CSharpSyntaxNode syntax = eventSymbol.CSharpSyntaxNode; TypeSymbol delegateType = eventSymbol.Type; MethodSymbol accessor = isAddMethod ? eventSymbol.AddMethod : eventSymbol.RemoveMethod; ParameterSymbol thisParameter = accessor.ThisParameter; TypeSymbol boolType = compilation.GetSpecialType(SpecialType.System_Boolean); SpecialMember updateMethodId = isAddMethod ? SpecialMember.System_Delegate__Combine : SpecialMember.System_Delegate__Remove; MethodSymbol updateMethod = (MethodSymbol)compilation.GetSpecialTypeMember(updateMethodId); BoundStatement @return = new BoundReturnStatement(syntax, refKind: RefKind.None, expressionOpt: null) { WasCompilerGenerated = true }; if (updateMethod == null) { MemberDescriptor memberDescriptor = SpecialMembers.GetDescriptor(updateMethodId); diagnostics.Add(new CSDiagnostic(new CSDiagnosticInfo(ErrorCode.ERR_MissingPredefinedMember, memberDescriptor.DeclaringTypeMetadataName, memberDescriptor.Name), syntax.Location)); return(BoundBlock.SynthesizedNoLocals(syntax, @return)); } Binder.ReportUseSite(updateMethod, diagnostics, syntax); BoundThisReference fieldReceiver = eventSymbol.IsStatic ? null : new BoundThisReference(syntax, thisParameter.Type) { WasCompilerGenerated = true }; BoundFieldAccess boundBackingField = new BoundFieldAccess(syntax, receiver: fieldReceiver, fieldSymbol: eventSymbol.AssociatedField, constantValueOpt: null) { WasCompilerGenerated = true }; BoundParameter boundParameter = new BoundParameter(syntax, parameterSymbol: accessor.Parameters[0]) { WasCompilerGenerated = true }; BoundExpression delegateUpdate; MethodSymbol compareExchangeMethod = (MethodSymbol)compilation.GetWellKnownTypeMember(WellKnownMember.System_Threading_Interlocked__CompareExchange_T); if ((object)compareExchangeMethod == null) { // (DelegateType)Delegate.Combine(_event, value) delegateUpdate = BoundConversion.SynthesizedNonUserDefined(syntax, operand: BoundCall.Synthesized(syntax, receiverOpt: null, method: updateMethod, arguments: ImmutableArray.Create <BoundExpression>(boundBackingField, boundParameter)), conversion: Conversion.ExplicitReference, type: delegateType); // _event = (DelegateType)Delegate.Combine(_event, value); BoundStatement eventUpdate = new BoundExpressionStatement(syntax, expression: new BoundAssignmentOperator(syntax, left: boundBackingField, right: delegateUpdate, type: delegateType) { WasCompilerGenerated = true }) { WasCompilerGenerated = true }; return(BoundBlock.SynthesizedNoLocals(syntax, statements: ImmutableArray.Create <BoundStatement>( eventUpdate, @return))); } compareExchangeMethod = compareExchangeMethod.Construct(ImmutableArray.Create <TypeSymbol>(delegateType)); Binder.ReportUseSite(compareExchangeMethod, diagnostics, syntax); GeneratedLabelSymbol loopLabel = new GeneratedLabelSymbol("loop"); const int numTemps = 3; LocalSymbol[] tmps = new LocalSymbol[numTemps]; BoundLocal[] boundTmps = new BoundLocal[numTemps]; for (int i = 0; i < numTemps; i++) { tmps[i] = new SynthesizedLocal(accessor, TypeWithAnnotations.Create(delegateType), SynthesizedLocalKind.LoweringTemp); boundTmps[i] = new BoundLocal(syntax, tmps[i], null, delegateType) { WasCompilerGenerated = true }; } // tmp0 = _event; BoundStatement tmp0Init = new BoundExpressionStatement(syntax, expression: new BoundAssignmentOperator(syntax, left: boundTmps[0], right: boundBackingField, type: delegateType) { WasCompilerGenerated = true }) { WasCompilerGenerated = true }; // LOOP: BoundStatement loopStart = new BoundLabelStatement(syntax, label: loopLabel) { WasCompilerGenerated = true }; // tmp1 = tmp0; BoundStatement tmp1Update = new BoundExpressionStatement(syntax, expression: new BoundAssignmentOperator(syntax, left: boundTmps[1], right: boundTmps[0], type: delegateType) { WasCompilerGenerated = true }) { WasCompilerGenerated = true }; // (DelegateType)Delegate.Combine(tmp1, value) delegateUpdate = BoundConversion.SynthesizedNonUserDefined(syntax, operand: BoundCall.Synthesized(syntax, receiverOpt: null, method: updateMethod, arguments: ImmutableArray.Create <BoundExpression>(boundTmps[1], boundParameter)), conversion: Conversion.ExplicitReference, type: delegateType); // tmp2 = (DelegateType)Delegate.Combine(tmp1, value); BoundStatement tmp2Update = new BoundExpressionStatement(syntax, expression: new BoundAssignmentOperator(syntax, left: boundTmps[2], right: delegateUpdate, type: delegateType) { WasCompilerGenerated = true }) { WasCompilerGenerated = true }; // Interlocked.CompareExchange<DelegateType>(ref _event, tmp2, tmp1) BoundExpression compareExchange = BoundCall.Synthesized(syntax, receiverOpt: null, method: compareExchangeMethod, arguments: ImmutableArray.Create <BoundExpression>(boundBackingField, boundTmps[2], boundTmps[1])); // tmp0 = Interlocked.CompareExchange<DelegateType>(ref _event, tmp2, tmp1); BoundStatement tmp0Update = new BoundExpressionStatement(syntax, expression: new BoundAssignmentOperator(syntax, left: boundTmps[0], right: compareExchange, type: delegateType) { WasCompilerGenerated = true }) { WasCompilerGenerated = true }; // tmp0 == tmp1 // i.e. exit when they are equal, jump to start otherwise BoundExpression loopExitCondition = new BoundBinaryOperator(syntax, operatorKind: BinaryOperatorKind.ObjectEqual, left: boundTmps[0], right: boundTmps[1], constantValueOpt: null, methodOpt: null, resultKind: LookupResultKind.Viable, type: boolType) { WasCompilerGenerated = true }; // branchfalse (tmp0 == tmp1) LOOP BoundStatement loopEnd = new BoundConditionalGoto(syntax, condition: loopExitCondition, jumpIfTrue: false, label: loopLabel) { WasCompilerGenerated = true }; return(new BoundBlock(syntax, locals: tmps.AsImmutable(), statements: ImmutableArray.Create <BoundStatement>( tmp0Init, loopStart, tmp1Update, tmp2Update, tmp0Update, loopEnd, @return)) { WasCompilerGenerated = true }); }
internal override MethodSymbol ConstructMethod(MethodSymbol method, ImmutableArray<TypeParameterSymbol> typeParameters, ImmutableArray<TypeSymbol> typeArguments) { var methodArity = method.Arity; var methodArgumentStartIndex = typeParameters.Length - methodArity; var typeMap = new TypeMap( ImmutableArray.Create(typeParameters, 0, methodArgumentStartIndex), ImmutableArray.CreateRange(typeArguments, 0, methodArgumentStartIndex, t => TypeWithAnnotations.Create(t))); var substitutedType = typeMap.SubstituteNamedType(method.ContainingType); method = method.AsMember(substitutedType); if (methodArity > 0) { method = method.Construct(ImmutableArray.Create(typeArguments, methodArgumentStartIndex, methodArity)); } return method; }
private DynamicAnalysisInjector( MethodSymbol method, BoundStatement methodBody, SyntheticBoundNodeFactory methodBodyFactory, MethodSymbol createPayloadForMethodsSpanningSingleFile, MethodSymbol createPayloadForMethodsSpanningMultipleFiles, DiagnosticBag diagnostics, DebugDocumentProvider debugDocumentProvider, Instrumenter previous) : base(previous) { _createPayloadForMethodsSpanningSingleFile = createPayloadForMethodsSpanningSingleFile; _createPayloadForMethodsSpanningMultipleFiles = createPayloadForMethodsSpanningMultipleFiles; _method = method; _methodBody = methodBody; _spansBuilder = ArrayBuilder <SourceSpan> .GetInstance(); TypeSymbol payloadElementType = methodBodyFactory.SpecialType(SpecialType.System_Boolean); _payloadType = ArrayTypeSymbol.CreateCSharpArray(methodBodyFactory.Compilation.Assembly, TypeWithAnnotations.Create(payloadElementType)); _diagnostics = diagnostics; _debugDocumentProvider = debugDocumentProvider; _methodBodyFactory = methodBodyFactory; // Set the factory context to generate nodes for the current method var oldMethod = methodBodyFactory.CurrentFunction; methodBodyFactory.CurrentFunction = method; _methodPayload = methodBodyFactory.SynthesizedLocal(_payloadType, kind: SynthesizedLocalKind.InstrumentationPayload, syntax: methodBody.Syntax); // The first point indicates entry into the method and has the span of the method definition. SyntaxNode syntax = MethodDeclarationIfAvailable(methodBody.Syntax); if (!method.IsImplicitlyDeclared && !(method is SynthesizedSimpleProgramEntryPointSymbol)) { _methodEntryInstrumentation = AddAnalysisPoint(syntax, SkipAttributes(syntax), methodBodyFactory); } // Restore context methodBodyFactory.CurrentFunction = oldMethod; }
// NOTE: Specifically not overriding IsIndirectlyInIterator. internal override TypeWithAnnotations GetIteratorElementType() { return(TypeWithAnnotations.Create(CreateErrorType())); }
/// <summary> /// Returns a constructed type given the type it is constructed from and type arguments for its enclosing types and itself. /// </summary> /// <param name="typeArguments">the type arguments that will replace the type parameters, starting with those for enclosing types</param> /// <returns></returns> private static NamedTypeSymbol DeepConstruct(NamedTypeSymbol type, ImmutableArray <TypeSymbol> typeArguments) { Assert.True(type.IsDefinition); var allTypeParameters = ArrayBuilder <TypeParameterSymbol> .GetInstance(); type.GetAllTypeParameters(allTypeParameters); return(new TypeMap(allTypeParameters.ToImmutableAndFree(), typeArguments.SelectAsArray(t => TypeWithAnnotations.Create(t))).SubstituteNamedType(type)); }
private static TypeWithAnnotations CreateType(TypeSymbol type, ImmutableArray <ModifierInfo <TypeSymbol> > customModifiers) { // The actual annotation will be set when these types are transformed by the caller. return(TypeWithAnnotations.Create(type, NullableAnnotation.Oblivious, CSharpCustomModifier.Convert(customModifiers))); }
public BoundDeconstructValuePlaceholder FailInference(Binder binder) { return(SetInferredTypeWithAnnotations(TypeWithAnnotations.Create(binder.CreateErrorType()), binder, success: false)); }
internal SynthesizedAttributeData SynthesizeTupleNamesAttribute(TypeSymbol type) { Debug.Assert((object)type != null); Debug.Assert(type.ContainsTuple()); var stringType = GetSpecialType(SpecialType.System_String); Debug.Assert((object)stringType != null); var names = TupleNamesEncoder.Encode(type, stringType); Debug.Assert(!names.IsDefault, "should not need the attribute when no tuple names"); var stringArray = ArrayTypeSymbol.CreateSZArray(stringType.ContainingAssembly, TypeWithAnnotations.Create(stringType)); var args = ImmutableArray.Create(new TypedConstant(stringArray, names)); return(TrySynthesizeAttribute(WellKnownMember.System_Runtime_CompilerServices_TupleElementNamesAttribute__ctorTransformNames, args)); }
public override BoundStatement CreateBlockPrologue(BoundBlock original, out LocalSymbol synthesizedLocal) { BoundStatement previousPrologue = base.CreateBlockPrologue(original, out synthesizedLocal); if (_methodBody == original) { _dynamicAnalysisSpans = _spansBuilder.ToImmutableAndFree(); // In the future there will be multiple analysis kinds. const int analysisKind = 0; ArrayTypeSymbol modulePayloadType = ArrayTypeSymbol.CreateCSharpArray(_methodBodyFactory.Compilation.Assembly, TypeWithAnnotations.Create(_payloadType)); // Synthesize the initialization of the instrumentation payload array, using concurrency-safe code: // // var payload = PID.PayloadRootField[methodIndex]; // if (payload == null) // payload = Instrumentation.CreatePayload(mvid, methodIndex, fileIndexOrIndices, ref PID.PayloadRootField[methodIndex], payloadLength); BoundStatement payloadInitialization = _methodBodyFactory.Assignment( _methodBodyFactory.Local(_methodPayload), _methodBodyFactory.ArrayAccess( _methodBodyFactory.InstrumentationPayloadRoot(analysisKind, modulePayloadType), ImmutableArray.Create(_methodBodyFactory.MethodDefIndex(_method)))); BoundExpression mvid = _methodBodyFactory.ModuleVersionId(); BoundExpression methodToken = _methodBodyFactory.MethodDefIndex(_method); BoundExpression payloadSlot = _methodBodyFactory.ArrayAccess( _methodBodyFactory.InstrumentationPayloadRoot(analysisKind, modulePayloadType), ImmutableArray.Create(_methodBodyFactory.MethodDefIndex(_method))); BoundStatement createPayloadCall = GetCreatePayloadStatement( _dynamicAnalysisSpans, _methodBody.Syntax, _methodPayload, _createPayloadForMethodsSpanningSingleFile, _createPayloadForMethodsSpanningMultipleFiles, mvid, methodToken, payloadSlot, _methodBodyFactory, _debugDocumentProvider); BoundExpression payloadNullTest = _methodBodyFactory.Binary( BinaryOperatorKind.ObjectEqual, _methodBodyFactory.SpecialType(SpecialType.System_Boolean), _methodBodyFactory.Local(_methodPayload), _methodBodyFactory.Null(_payloadType)); BoundStatement payloadIf = _methodBodyFactory.If(payloadNullTest, createPayloadCall); Debug.Assert(synthesizedLocal == null); synthesizedLocal = _methodPayload; ArrayBuilder <BoundStatement> prologueStatements = ArrayBuilder <BoundStatement> .GetInstance(previousPrologue == null? 3 : 4); prologueStatements.Add(payloadInitialization); prologueStatements.Add(payloadIf); if (_methodEntryInstrumentation != null) { prologueStatements.Add(_methodEntryInstrumentation); } if (previousPrologue != null) { prologueStatements.Add(previousPrologue); } return(_methodBodyFactory.StatementList(prologueStatements.ToImmutableAndFree())); } return(previousPrologue); }
/// <summary> /// Given a type <paramref name="type"/>, which is either dynamic type OR is a constructed type with dynamic type present in it's type argument tree, /// returns a synthesized DynamicAttribute with encoded dynamic transforms array. /// </summary> /// <remarks>This method is port of AttrBind::CompileDynamicAttr from the native C# compiler.</remarks> internal SynthesizedAttributeData SynthesizeDynamicAttribute(TypeSymbol type, int customModifiersCount, RefKind refKindOpt = RefKind.None) { Debug.Assert((object)type != null); Debug.Assert(type.ContainsDynamic()); if (type.IsDynamic() && refKindOpt == RefKind.None && customModifiersCount == 0) { return(TrySynthesizeAttribute(WellKnownMember.System_Runtime_CompilerServices_DynamicAttribute__ctor)); } else { NamedTypeSymbol booleanType = GetSpecialType(SpecialType.System_Boolean); Debug.Assert((object)booleanType != null); var transformFlags = DynamicTransformsEncoder.Encode(type, refKindOpt, customModifiersCount, booleanType); var boolArray = ArrayTypeSymbol.CreateSZArray(booleanType.ContainingAssembly, TypeWithAnnotations.Create(booleanType)); var arguments = ImmutableArray.Create <TypedConstant>(new TypedConstant(boolArray, transformFlags)); return(TrySynthesizeAttribute(WellKnownMember.System_Runtime_CompilerServices_DynamicAttribute__ctorTransformFlags, arguments)); } }
private PEParameterSymbol( PEModuleSymbol moduleSymbol, Symbol containingSymbol, int ordinal, bool isByRef, TypeWithAnnotations typeWithAnnotations, ImmutableArray <byte> extraAnnotations, ParameterHandle handle, int countOfCustomModifiers, out bool isBad) { Debug.Assert((object)moduleSymbol != null); Debug.Assert((object)containingSymbol != null); Debug.Assert(ordinal >= 0); Debug.Assert(typeWithAnnotations.HasType); isBad = false; _moduleSymbol = moduleSymbol; _containingSymbol = containingSymbol; _ordinal = (ushort)ordinal; _handle = handle; RefKind refKind = RefKind.None; if (handle.IsNil) { refKind = isByRef ? RefKind.Ref : RefKind.None; typeWithAnnotations = TupleTypeSymbol.TryTransformToTuple(typeWithAnnotations.Type, out TupleTypeSymbol tuple) ? TypeWithAnnotations.Create(tuple) : typeWithAnnotations; if (!extraAnnotations.IsDefault) { typeWithAnnotations = NullableTypeDecoder.TransformType(typeWithAnnotations, defaultTransformFlag: 0, extraAnnotations); } _lazyCustomAttributes = ImmutableArray <CSharpAttributeData> .Empty; _lazyHiddenAttributes = ImmutableArray <CSharpAttributeData> .Empty; _lazyDefaultValue = ConstantValue.NotAvailable; _lazyIsParams = ThreeState.False; } else { try { moduleSymbol.Module.GetParamPropsOrThrow(handle, out _name, out _flags); } catch (BadImageFormatException) { isBad = true; } if (isByRef) { ParameterAttributes inOutFlags = _flags & (ParameterAttributes.Out | ParameterAttributes.In); if (inOutFlags == ParameterAttributes.Out) { refKind = RefKind.Out; } else if (moduleSymbol.Module.HasIsReadOnlyAttribute(handle)) { refKind = RefKind.In; } else { refKind = RefKind.Ref; } } // CONSIDER: Can we make parameter type computation lazy? var typeSymbol = DynamicTypeDecoder.TransformType(typeWithAnnotations.Type, countOfCustomModifiers, handle, moduleSymbol, refKind); typeWithAnnotations = typeWithAnnotations.WithTypeAndModifiers(typeSymbol, typeWithAnnotations.CustomModifiers); // Decode nullable before tuple types to avoid converting between // NamedTypeSymbol and TupleTypeSymbol unnecessarily. typeWithAnnotations = NullableTypeDecoder.TransformType(typeWithAnnotations, handle, moduleSymbol, extraAnnotations); typeWithAnnotations = TupleTypeDecoder.DecodeTupleTypesIfApplicable(typeWithAnnotations, handle, moduleSymbol); } _typeWithAnnotations = typeWithAnnotations; bool hasNameInMetadata = !string.IsNullOrEmpty(_name); if (!hasNameInMetadata) { // As was done historically, if the parameter doesn't have a name, we give it the name "value". _name = "value"; } _packedFlags = new PackedFlags(refKind, attributesAreComplete: handle.IsNil, hasNameInMetadata: hasNameInMetadata); Debug.Assert(refKind == this.RefKind); Debug.Assert(hasNameInMetadata == this.HasNameInMetadata); }
public void TestArrayType() { CSharpCompilation compilation = CSharpCompilation.Create("Test"); NamedTypeSymbol elementType = new MockNamedTypeSymbol("TestClass", Enumerable.Empty <Symbol>()); // this can be any type. ArrayTypeSymbol ats1 = ArrayTypeSymbol.CreateCSharpArray(compilation.Assembly, TypeWithAnnotations.Create(elementType), rank: 1); Assert.Equal(1, ats1.Rank); Assert.True(ats1.IsSZArray); Assert.Same(elementType, ats1.ElementType); Assert.Equal(SymbolKind.ArrayType, ats1.Kind); Assert.True(ats1.IsReferenceType); Assert.False(ats1.IsValueType); Assert.Equal("TestClass[]", ats1.ToTestDisplayString()); ArrayTypeSymbol ats2 = ArrayTypeSymbol.CreateCSharpArray(compilation.Assembly, TypeWithAnnotations.Create(elementType), rank: 2); Assert.Equal(2, ats2.Rank); Assert.Same(elementType, ats2.ElementType); Assert.Equal(SymbolKind.ArrayType, ats2.Kind); Assert.True(ats2.IsReferenceType); Assert.False(ats2.IsValueType); Assert.Equal("TestClass[,]", ats2.ToTestDisplayString()); ArrayTypeSymbol ats3 = ArrayTypeSymbol.CreateCSharpArray(compilation.Assembly, TypeWithAnnotations.Create(elementType), rank: 3); Assert.Equal(3, ats3.Rank); Assert.Equal("TestClass[,,]", ats3.ToTestDisplayString()); }
private ImmutableArray <TypeWithAnnotations> GetDeclaredConstraintTypes() { if (_lazyDeclaredConstraintTypes.IsDefault) { ImmutableArray <TypeWithAnnotations> declaredConstraintTypes; PEMethodSymbol containingMethod = null; PENamedTypeSymbol containingType; if (_containingSymbol.Kind == SymbolKind.Method) { containingMethod = (PEMethodSymbol)_containingSymbol; containingType = (PENamedTypeSymbol)containingMethod.ContainingSymbol; } else { containingType = (PENamedTypeSymbol)_containingSymbol; } var moduleSymbol = containingType.ContainingPEModule; PEModule peModule = moduleSymbol.Module; GenericParameterConstraintHandleCollection constraints = GetConstraintHandleCollection(peModule); bool hasUnmanagedModreqPattern = false; if (constraints.Count > 0) { var symbolsBuilder = ArrayBuilder <TypeWithAnnotations> .GetInstance(); MetadataDecoder tokenDecoder; if ((object)containingMethod != null) { tokenDecoder = new MetadataDecoder(moduleSymbol, containingMethod); } else { tokenDecoder = new MetadataDecoder(moduleSymbol, containingType); } var metadataReader = peModule.MetadataReader; foreach (var constraintHandle in constraints) { var constraint = metadataReader.GetGenericParameterConstraint(constraintHandle); var typeSymbol = tokenDecoder.DecodeGenericParameterConstraint(constraint.Type, out bool hasUnmanagedModreq); if (typeSymbol.SpecialType == SpecialType.System_ValueType) { // recognize "(class [mscorlib]System.ValueType modreq([mscorlib]System.Runtime.InteropServices.UnmanagedType" pattern as "unmanaged" if (hasUnmanagedModreq) { hasUnmanagedModreqPattern = true; } // Drop 'System.ValueType' constraint type if the 'valuetype' constraint was also specified. if (((_flags & GenericParameterAttributes.NotNullableValueTypeConstraint) != 0)) { continue; } } var type = TypeWithAnnotations.Create(typeSymbol); type = NullableTypeDecoder.TransformType(type, constraintHandle, moduleSymbol); // Drop 'System.Object?' constraint type. if (type.SpecialType == SpecialType.System_Object && type.NullableAnnotation.IsAnnotated()) { continue; } type = TupleTypeDecoder.DecodeTupleTypesIfApplicable(type, constraintHandle, moduleSymbol); symbolsBuilder.Add(type); } declaredConstraintTypes = symbolsBuilder.ToImmutableAndFree(); } else { declaredConstraintTypes = ImmutableArray <TypeWithAnnotations> .Empty; } // - presence of unmanaged pattern has to be matched with `valuetype` // - IsUnmanagedAttribute is allowed iif there is an unmanaged pattern if (hasUnmanagedModreqPattern && (_flags & GenericParameterAttributes.NotNullableValueTypeConstraint) == 0 || hasUnmanagedModreqPattern != peModule.HasIsUnmanagedAttribute(_handle)) { // we do not recognize these combinations as "unmanaged" hasUnmanagedModreqPattern = false; Interlocked.CompareExchange(ref _lazyConstraintsUseSiteErrorInfo, new CSDiagnosticInfo(ErrorCode.ERR_BindToBogus, this), CSDiagnosticInfo.EmptyErrorInfo); } _lazyHasIsUnmanagedConstraint = hasUnmanagedModreqPattern.ToThreeState(); ImmutableInterlocked.InterlockedInitialize(ref _lazyDeclaredConstraintTypes, declaredConstraintTypes); } return(_lazyDeclaredConstraintTypes); }
internal override void GenerateMethodBody(TypeCompilationState compilationState, BindingDiagnosticBag diagnostics) { ImmutableArray <LocalSymbol> declaredLocalsArray; var body = _generateMethodBody(this, diagnostics.DiagnosticBag, out declaredLocalsArray, out _lazyResultProperties); var compilation = compilationState.Compilation; _lazyReturnType = TypeWithAnnotations.Create(CalculateReturnType(compilation, body)); // Can't do this until the return type has been computed. TypeParameterChecker.Check(this, _allTypeParameters); if (diagnostics.HasAnyErrors()) { return; } DiagnosticsPass.IssueDiagnostics(compilation, body, diagnostics, this); if (diagnostics.HasAnyErrors()) { return; } // Check for use-site diagnostics (e.g. missing types in the signature). UseSiteInfo <AssemblySymbol> useSiteInfo = default; this.CalculateUseSiteDiagnostic(ref useSiteInfo); if (useSiteInfo.DiagnosticInfo != null && useSiteInfo.DiagnosticInfo.Severity == DiagnosticSeverity.Error) { diagnostics.Add(useSiteInfo.DiagnosticInfo, this.Locations[0]); return; } try { var declaredLocals = PooledHashSet <LocalSymbol> .GetInstance(); try { // Rewrite local declaration statement. body = (BoundStatement)LocalDeclarationRewriter.Rewrite( compilation, _container, declaredLocals, body, declaredLocalsArray, diagnostics.DiagnosticBag); // Verify local declaration names. foreach (var local in declaredLocals) { Debug.Assert(local.Locations.Length > 0); var name = local.Name; if (name.StartsWith("$", StringComparison.Ordinal)) { diagnostics.Add(ErrorCode.ERR_UnexpectedCharacter, local.Locations[0], name[0]); return; } } // Rewrite references to placeholder "locals". body = (BoundStatement)PlaceholderLocalRewriter.Rewrite(compilation, _container, declaredLocals, body, diagnostics.DiagnosticBag); if (diagnostics.HasAnyErrors()) { return; } } finally { declaredLocals.Free(); } var syntax = body.Syntax; var statementsBuilder = ArrayBuilder <BoundStatement> .GetInstance(); statementsBuilder.Add(body); // Insert an implicit return statement if necessary. if (body.Kind != BoundKind.ReturnStatement) { statementsBuilder.Add(new BoundReturnStatement(syntax, RefKind.None, expressionOpt: null)); } var localsSet = PooledHashSet <LocalSymbol> .GetInstance(); try { var localsBuilder = ArrayBuilder <LocalSymbol> .GetInstance(); foreach (var local in this.LocalsForBinding) { Debug.Assert(!localsSet.Contains(local)); localsBuilder.Add(local); localsSet.Add(local); } foreach (var local in this.Locals) { if (localsSet.Add(local)) { localsBuilder.Add(local); } } body = new BoundBlock(syntax, localsBuilder.ToImmutableAndFree(), statementsBuilder.ToImmutableAndFree()) { WasCompilerGenerated = true }; Debug.Assert(!diagnostics.HasAnyErrors()); Debug.Assert(!body.HasErrors); bool sawLambdas; bool sawLocalFunctions; bool sawAwaitInExceptionHandler; ImmutableArray <SourceSpan> dynamicAnalysisSpans = ImmutableArray <SourceSpan> .Empty; body = LocalRewriter.Rewrite( compilation: this.DeclaringCompilation, method: this, methodOrdinal: _methodOrdinal, containingType: _container, statement: body, compilationState: compilationState, previousSubmissionFields: null, allowOmissionOfConditionalCalls: false, instrumentForDynamicAnalysis: false, debugDocumentProvider: null, dynamicAnalysisSpans: ref dynamicAnalysisSpans, diagnostics: diagnostics, sawLambdas: out sawLambdas, sawLocalFunctions: out sawLocalFunctions, sawAwaitInExceptionHandler: out sawAwaitInExceptionHandler); Debug.Assert(!sawAwaitInExceptionHandler); Debug.Assert(dynamicAnalysisSpans.Length == 0); if (body.HasErrors) { return; } // Variables may have been captured by lambdas in the original method // or in the expression, and we need to preserve the existing values of // those variables in the expression. This requires rewriting the variables // in the expression based on the closure classes from both the original // method and the expression, and generating a preamble that copies // values into the expression closure classes. // // Consider the original method: // static void M() // { // int x, y, z; // ... // F(() => x + y); // } // and the expression in the EE: "F(() => x + z)". // // The expression is first rewritten using the closure class and local <1> // from the original method: F(() => <1>.x + z) // Then lambda rewriting introduces a new closure class that includes // the locals <1> and z, and a corresponding local <2>: F(() => <2>.<1>.x + <2>.z) // And a preamble is added to initialize the fields of <2>: // <2> = new <>c__DisplayClass0(); // <2>.<1> = <1>; // <2>.z = z; // Rewrite "this" and "base" references to parameter in this method. // Rewrite variables within body to reference existing display classes. body = (BoundStatement)CapturedVariableRewriter.Rewrite( this.GenerateThisReference, compilation.Conversions, _displayClassVariables, body, diagnostics.DiagnosticBag); if (body.HasErrors) { Debug.Assert(false, "Please add a test case capturing whatever caused this assert."); return; } if (diagnostics.HasAnyErrors()) { return; } if (sawLambdas || sawLocalFunctions) { var closureDebugInfoBuilder = ArrayBuilder <ClosureDebugInfo> .GetInstance(); var lambdaDebugInfoBuilder = ArrayBuilder <LambdaDebugInfo> .GetInstance(); body = ClosureConversion.Rewrite( loweredBody: body, thisType: this.SubstitutedSourceMethod.ContainingType, thisParameter: _thisParameter, method: this, methodOrdinal: _methodOrdinal, substitutedSourceMethod: this.SubstitutedSourceMethod.OriginalDefinition, closureDebugInfoBuilder: closureDebugInfoBuilder, lambdaDebugInfoBuilder: lambdaDebugInfoBuilder, slotAllocatorOpt: null, compilationState: compilationState, diagnostics: diagnostics, assignLocals: localsSet); // we don't need this information: closureDebugInfoBuilder.Free(); lambdaDebugInfoBuilder.Free(); } } finally { localsSet.Free(); } // Insert locals from the original method, // followed by any new locals. var block = (BoundBlock)body; var localBuilder = ArrayBuilder <LocalSymbol> .GetInstance(); foreach (var local in this.Locals) { Debug.Assert(!(local is EELocalSymbol) || (((EELocalSymbol)local).Ordinal == localBuilder.Count)); localBuilder.Add(local); } foreach (var local in block.Locals) { if (local is EELocalSymbol oldLocal) { Debug.Assert(localBuilder[oldLocal.Ordinal] == oldLocal); continue; } localBuilder.Add(local); } body = block.Update(localBuilder.ToImmutableAndFree(), block.LocalFunctions, block.Statements); TypeParameterChecker.Check(body, _allTypeParameters); compilationState.AddSynthesizedMethod(this, body); } catch (BoundTreeVisitor.CancelledByStackGuardException ex) { ex.AddAnError(diagnostics); } }
private static TypeSymbol?MakeMergedTupleType(ArrayBuilder <DeconstructionVariable> lhsVariables, BoundTupleLiteral rhsLiteral, CSharpSyntaxNode syntax, CSharpCompilation compilation, DiagnosticBag?diagnostics) { int leftLength = lhsVariables.Count; int rightLength = rhsLiteral.Arguments.Length; var typesWithAnnotationsBuilder = ArrayBuilder <TypeWithAnnotations> .GetInstance(leftLength); var locationsBuilder = ArrayBuilder <Location?> .GetInstance(leftLength); for (int i = 0; i < rightLength; i++) { BoundExpression element = rhsLiteral.Arguments[i]; TypeSymbol? mergedType = element.Type; if (i < leftLength) { var variable = lhsVariables[i]; if (variable.NestedVariables is object) { if (element.Kind == BoundKind.TupleLiteral) { // (variables) on the left and (elements) on the right mergedType = MakeMergedTupleType(variable.NestedVariables, (BoundTupleLiteral)element, syntax, compilation, diagnostics); } else if ((object?)mergedType == null && diagnostics is object) { // (variables) on the left and null on the right Error(diagnostics, ErrorCode.ERR_DeconstructRequiresExpression, element.Syntax); } } else { Debug.Assert(variable.Single is object); if ((object?)variable.Single.Type != null) { // typed-variable on the left mergedType = variable.Single.Type; } } } else { if ((object?)mergedType == null && diagnostics is object) { // a typeless element on the right, matching no variable on the left Error(diagnostics, ErrorCode.ERR_DeconstructRequiresExpression, element.Syntax); } } typesWithAnnotationsBuilder.Add(TypeWithAnnotations.Create(mergedType)); locationsBuilder.Add(element.Syntax.Location); } if (typesWithAnnotationsBuilder.Any(t => !t.HasType)) { typesWithAnnotationsBuilder.Free(); locationsBuilder.Free(); return(null); } // The tuple created here is not identical to the one created by // DeconstructionVariablesAsTuple. It represents a smaller // tree of types used for figuring out natural types in tuple literal. return(NamedTypeSymbol.CreateTuple( locationOpt: null, elementTypesWithAnnotations: typesWithAnnotationsBuilder.ToImmutableAndFree(), elementLocations: locationsBuilder.ToImmutableAndFree(), elementNames: default(ImmutableArray <string?>), compilation: compilation, diagnostics: diagnostics, shouldCheckConstraints: true, includeNullability: false, errorPositions: default(ImmutableArray <bool>), syntax: syntax)); }
private static bool CanUnifyHelper(TypeSymbol t1, TypeSymbol t2, ref MutableTypeMap substitution) { return(CanUnifyHelper(TypeWithAnnotations.Create(t1), TypeWithAnnotations.Create(t2), ref substitution)); }
internal PEEventSymbol( PEModuleSymbol moduleSymbol, PENamedTypeSymbol containingType, EventDefinitionHandle handle, PEMethodSymbol addMethod, PEMethodSymbol removeMethod, MultiDictionary <string, PEFieldSymbol> privateFieldNameToSymbols) { RoslynDebug.Assert((object)moduleSymbol != null); RoslynDebug.Assert((object)containingType != null); Debug.Assert(!handle.IsNil); RoslynDebug.Assert((object)addMethod != null); RoslynDebug.Assert((object)removeMethod != null); _addMethod = addMethod; _removeMethod = removeMethod; _handle = handle; _containingType = containingType; EventAttributes mdFlags = 0; EntityHandle eventType = default(EntityHandle); try { var module = moduleSymbol.Module; module.GetEventDefPropsOrThrow(handle, out _name, out mdFlags, out eventType); } catch (BadImageFormatException mrEx) { _name = _name ?? string.Empty; _lazyUseSiteDiagnostic = new CSDiagnosticInfo(ErrorCode.ERR_BindToBogus, this); if (eventType.IsNil) { _eventTypeWithAnnotations = TypeWithAnnotations.Create(new UnsupportedMetadataTypeSymbol(mrEx)); } } TypeSymbol originalEventType = _eventTypeWithAnnotations.Type; if (!_eventTypeWithAnnotations.HasType) { var metadataDecoder = new MetadataDecoder(moduleSymbol, containingType); originalEventType = metadataDecoder.GetTypeOfToken(eventType); const int targetSymbolCustomModifierCount = 0; var typeSymbol = DynamicTypeDecoder.TransformType(originalEventType, targetSymbolCustomModifierCount, handle, moduleSymbol); typeSymbol = NativeIntegerTypeDecoder.TransformType(typeSymbol, handle, moduleSymbol); // We start without annotation (they will be decoded below) var type = TypeWithAnnotations.Create(typeSymbol); // Decode nullable before tuple types to avoid converting between // NamedTypeSymbol and TupleTypeSymbol unnecessarily. // The containing type is passed to NullableTypeDecoder.TransformType to determine access // because the event does not have explicit accessibility in metadata. type = NullableTypeDecoder.TransformType(type, handle, moduleSymbol, accessSymbol: _containingType, nullableContext: _containingType); type = TupleTypeDecoder.DecodeTupleTypesIfApplicable(type, handle, moduleSymbol); _eventTypeWithAnnotations = type; } // IsWindowsRuntimeEvent checks the signatures, so we just have to check the accessors. bool isWindowsRuntimeEvent = IsWindowsRuntimeEvent; bool callMethodsDirectly = isWindowsRuntimeEvent ? !DoModifiersMatch(_addMethod, _removeMethod) : !DoSignaturesMatch(moduleSymbol, originalEventType, _addMethod, _removeMethod); if (callMethodsDirectly) { _flags |= Flags.CallMethodsDirectly; } else { _addMethod.SetAssociatedEvent(this, MethodKind.EventAdd); _removeMethod.SetAssociatedEvent(this, MethodKind.EventRemove); PEFieldSymbol?associatedField = GetAssociatedField(privateFieldNameToSymbols, isWindowsRuntimeEvent); if ((object?)associatedField != null) { _associatedFieldOpt = associatedField; associatedField.SetAssociatedEvent(this); } } if ((mdFlags & EventAttributes.SpecialName) != 0) { _flags |= Flags.IsSpecialName; } if ((mdFlags & EventAttributes.RTSpecialName) != 0) { _flags |= Flags.IsRuntimeSpecialName; } }
/// <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); } } }
/// <summary> /// This method recurses through leftTargets, right and conversion at the same time. /// As it does, it collects side-effects into the proper buckets (init, deconstructions, conversions, assignments). /// /// The side-effects from the right initially go into the init bucket. But once we started drilling into a Deconstruct /// invocation, subsequent side-effects from the right go into the deconstructions bucket (otherwise they would /// be evaluated out of order). /// </summary> private BoundExpression ApplyDeconstructionConversion(ArrayBuilder <Binder.DeconstructionVariable> leftTargets, BoundExpression right, Conversion conversion, ArrayBuilder <LocalSymbol> temps, DeconstructionSideEffects effects, bool isUsed, bool inInit) { Debug.Assert(conversion.Kind == ConversionKind.Deconstruction); ImmutableArray <BoundExpression> rightParts = GetRightParts(right, conversion, temps, effects, ref inInit); ImmutableArray <Conversion> underlyingConversions = conversion.UnderlyingConversions; Debug.Assert(!underlyingConversions.IsDefault); Debug.Assert(leftTargets.Count == rightParts.Length && leftTargets.Count == conversion.UnderlyingConversions.Length); var builder = isUsed ? ArrayBuilder <BoundExpression> .GetInstance(leftTargets.Count) : null; for (int i = 0; i < leftTargets.Count; i++) { BoundExpression resultPart; if (leftTargets[i].HasNestedVariables) { resultPart = ApplyDeconstructionConversion(leftTargets[i].NestedVariables, rightParts[i], underlyingConversions[i], temps, effects, isUsed, inInit); } else { var rightPart = rightParts[i]; if (inInit) { rightPart = EvaluateSideEffectingArgumentToTemp(VisitExpression(rightPart), effects.init, temps); } BoundExpression leftTarget = leftTargets[i].Single; resultPart = EvaluateConversionToTemp(rightPart, underlyingConversions[i], leftTarget.Type, temps, effects.conversions); if (leftTarget.Kind != BoundKind.DiscardExpression) { effects.assignments.Add(MakeAssignmentOperator(resultPart.Syntax, leftTarget, resultPart, leftTarget.Type, used: true, isChecked: false, isCompoundAssignment: false)); } } builder?.Add(resultPart); } if (isUsed) { var tupleType = TupleTypeSymbol.Create(locationOpt: null, elementTypesWithAnnotations: builder.SelectAsArray(e => TypeWithAnnotations.Create(e.Type)), elementLocations: default, elementNames: default,
public BoundTypeExpression(SyntaxNode syntax, AliasSymbol aliasOpt, TypeSymbol type, bool hasErrors = false) : this(syntax, aliasOpt, null, TypeWithAnnotations.Create(type), hasErrors) { }
internal BoundExpression SetInferredTypeWithAnnotations(TypeWithAnnotations type, Binder binderOpt, DiagnosticBag diagnosticsOpt) { Debug.Assert(binderOpt != null || type.HasType); Debug.Assert(this.Syntax.Kind() == SyntaxKind.SingleVariableDesignation || (this.Syntax.Kind() == SyntaxKind.DeclarationExpression && ((DeclarationExpressionSyntax)this.Syntax).Designation.Kind() == SyntaxKind.SingleVariableDesignation)); bool inferenceFailed = !type.HasType; if (inferenceFailed) { type = TypeWithAnnotations.Create(binderOpt.CreateErrorType("var")); } switch (this.VariableSymbol.Kind) { case SymbolKind.Local: var localSymbol = (SourceLocalSymbol)this.VariableSymbol; if (diagnosticsOpt != null) { if (inferenceFailed) { ReportInferenceFailure(diagnosticsOpt); } else { SyntaxNode typeOrDesignationSyntax = this.Syntax.Kind() == SyntaxKind.DeclarationExpression ? ((DeclarationExpressionSyntax)this.Syntax).Type : this.Syntax; Binder.CheckRestrictedTypeInAsync(localSymbol.ContainingSymbol, type.Type, diagnosticsOpt, typeOrDesignationSyntax); } } localSymbol.SetTypeWithAnnotations(type); return(new BoundLocal(this.Syntax, localSymbol, BoundLocalDeclarationKind.WithInferredType, constantValueOpt: null, isNullableUnknown: false, type: type.Type, hasErrors: this.HasErrors || inferenceFailed)); case SymbolKind.Field: var fieldSymbol = (GlobalExpressionVariable)this.VariableSymbol; var inferenceDiagnostics = DiagnosticBag.GetInstance(); if (inferenceFailed) { ReportInferenceFailure(inferenceDiagnostics); } type = fieldSymbol.SetTypeWithAnnotations(type, inferenceDiagnostics); inferenceDiagnostics.Free(); return(new BoundFieldAccess(this.Syntax, this.ReceiverOpt, fieldSymbol, null, LookupResultKind.Viable, isDeclaration: true, type: type.Type, hasErrors: this.HasErrors || inferenceFailed)); default: throw ExceptionUtilities.UnexpectedValue(this.VariableSymbol.Kind); } }
public void VisitWithNullableAnnotation(TypeSymbol symbol, NullableAnnotation topLevelAnnotation) { VisitWithAnnotation(TypeWithAnnotations.Create(symbol, topLevelAnnotation)); }
public AwaitCatchFrame(SyntheticBoundNodeFactory F, TryStatementSyntax tryStatementSyntax) { this.pendingCaughtException = new SynthesizedLocal(F.CurrentFunction, TypeWithAnnotations.Create(F.SpecialType(SpecialType.System_Object)), SynthesizedLocalKind.TryAwaitPendingCaughtException, tryStatementSyntax); this.pendingCatch = new SynthesizedLocal(F.CurrentFunction, TypeWithAnnotations.Create(F.SpecialType(SpecialType.System_Int32)), SynthesizedLocalKind.TryAwaitPendingCatch, tryStatementSyntax); this.handlers = new List <BoundBlock>(); _hoistedLocals = new Dictionary <LocalSymbol, LocalSymbol>(); _orderedHoistedLocals = new List <LocalSymbol>(); }
private BoundExpression BindAnonymousObjectCreation(AnonymousObjectCreationExpressionSyntax node, DiagnosticBag diagnostics) { // prepare var initializers = node.Initializers; int fieldCount = initializers.Count; bool hasError = false; // bind field initializers BoundExpression[] boundExpressions = new BoundExpression[fieldCount]; AnonymousTypeField[] fields = new AnonymousTypeField[fieldCount]; CSharpSyntaxNode[] fieldSyntaxNodes = new CSharpSyntaxNode[fieldCount]; // WARNING: Note that SemanticModel.GetDeclaredSymbol for field initializer node relies on // the fact that the order of properties in anonymous type template corresponds // 1-to-1 to the appropriate filed initializer syntax nodes; This means such // correspondence must be preserved all the time including erroneous scenarios // set of names already used var uniqueFieldNames = PooledHashSet <string> .GetInstance(); for (int i = 0; i < fieldCount; i++) { AnonymousObjectMemberDeclaratorSyntax fieldInitializer = initializers[i]; NameEqualsSyntax nameEquals = fieldInitializer.NameEquals; ExpressionSyntax expression = fieldInitializer.Expression; SyntaxToken nameToken = default(SyntaxToken); if (nameEquals != null) { nameToken = nameEquals.Name.Identifier; } else { if (!IsAnonymousTypeMemberExpression(expression)) { hasError = true; diagnostics.Add(ErrorCode.ERR_InvalidAnonymousTypeMemberDeclarator, expression.GetLocation()); } nameToken = expression.ExtractAnonymousTypeMemberName(); } hasError |= expression.HasErrors; boundExpressions[i] = BindRValueWithoutTargetType(expression, diagnostics); // check the name to be unique string fieldName = null; if (nameToken.Kind() == SyntaxKind.IdentifierToken) { fieldName = nameToken.ValueText; if (!uniqueFieldNames.Add(fieldName)) { // name duplication Error(diagnostics, ErrorCode.ERR_AnonymousTypeDuplicatePropertyName, fieldInitializer); hasError = true; fieldName = null; } } else { // there is something wrong with field's name hasError = true; } // calculate the expression's type and report errors if needed TypeSymbol fieldType = GetAnonymousTypeFieldType(boundExpressions[i], fieldInitializer, diagnostics, ref hasError); // build anonymous type field descriptor fieldSyntaxNodes[i] = (nameToken.Kind() == SyntaxKind.IdentifierToken) ? (CSharpSyntaxNode)nameToken.Parent : fieldInitializer; fields[i] = new AnonymousTypeField( fieldName == null ? "$" + i.ToString() : fieldName, fieldSyntaxNodes[i].Location, TypeWithAnnotations.Create(fieldType)); // NOTE: ERR_InvalidAnonymousTypeMemberDeclarator (CS0746) would be generated by parser if needed } uniqueFieldNames.Free(); // Create anonymous type AnonymousTypeManager manager = this.Compilation.AnonymousTypeManager; AnonymousTypeDescriptor descriptor = new AnonymousTypeDescriptor(fields.AsImmutableOrNull(), node.NewKeyword.GetLocation()); NamedTypeSymbol anonymousType = manager.ConstructAnonymousTypeSymbol(descriptor); // declarators - bound nodes created for providing semantic info // on anonymous type fields having explicitly specified name ArrayBuilder <BoundAnonymousPropertyDeclaration> declarators = ArrayBuilder <BoundAnonymousPropertyDeclaration> .GetInstance(); for (int i = 0; i < fieldCount; i++) { NameEqualsSyntax explicitName = initializers[i].NameEquals; if (explicitName != null) { AnonymousTypeField field = fields[i]; if (field.Name != null) { // get property symbol and create a bound property declaration node foreach (var symbol in anonymousType.GetMembers(field.Name)) { if (symbol.Kind == SymbolKind.Property) { declarators.Add(new BoundAnonymousPropertyDeclaration(fieldSyntaxNodes[i], (PropertySymbol)symbol, field.Type)); break; } } } } } // check if anonymous object creation is allowed in this context if (!this.IsAnonymousTypesAllowed()) { Error(diagnostics, ErrorCode.ERR_AnonymousTypeNotAvailable, node.NewKeyword); hasError = true; } // Finally create a bound node return(new BoundAnonymousObjectCreationExpression( node, anonymousType.InstanceConstructors[0], boundExpressions.AsImmutableOrNull(), declarators.ToImmutableAndFree(), anonymousType, hasError)); }
public LabelSymbol ProxyReturnIfNeeded( MethodSymbol containingMethod, BoundExpression valueOpt, out SynthesizedLocal returnValue) { returnValue = null; // no need to proxy returns at the root if (this.IsRoot()) { return(null); } var returnProxy = this.returnProxyLabel; if (returnProxy == null) { this.returnProxyLabel = returnProxy = new GeneratedLabelSymbol("returnProxy"); } if (valueOpt != null) { returnValue = this.returnValue; if (returnValue == null) { Debug.Assert(_statementSyntaxOpt != null); this.returnValue = returnValue = new SynthesizedLocal(containingMethod, TypeWithAnnotations.Create(valueOpt.Type), SynthesizedLocalKind.AsyncMethodReturnValue, _statementSyntaxOpt); } } return(returnProxy); }
/// <summary> /// Make a tuple type (with appropriate nesting) from the types (on the left or on the right) collected /// from binding element-wise binary operators. /// If any of the elements is typeless, then the tuple is typeless too. /// </summary> private TypeSymbol MakeConvertedType(ImmutableArray <TypeSymbol> convertedTypes, CSharpSyntaxNode syntax, ImmutableArray <BoundExpression> elements, ImmutableArray <string> names, bool isNullable, CSharpCompilation compilation, DiagnosticBag diagnostics) { foreach (var convertedType in convertedTypes) { if (convertedType is null) { return(null); } } ImmutableArray <Location> elementLocations = elements.SelectAsArray(e => e.Syntax.Location); var tuple = TupleTypeSymbol.Create(locationOpt: null, elementTypesWithAnnotations: convertedTypes.SelectAsArray(t => TypeWithAnnotations.Create(t)), elementLocations, elementNames: names, compilation, shouldCheckConstraints: true, includeNullability: false, errorPositions: default, syntax, diagnostics);
LearnFromDecisionDag( SyntaxNode node, BoundDecisionDag decisionDag, BoundExpression expression, TypeWithState expressionType, ref LocalState initialState) { // We reuse the slot at the beginning of a switch (or is-pattern expression), pretending that we are // not copying the input to evaluate the patterns. In this way we infer non-nullability of the original // variable's parts based on matched pattern parts. Mutations in `when` clauses can show the inaccuracy // of analysis based on this choice. var rootTemp = BoundDagTemp.ForOriginalInput(expression); int originalInputSlot = MakeSlot(expression); if (originalInputSlot <= 0) { originalInputSlot = makeDagTempSlot(expressionType.ToTypeWithAnnotations(), rootTemp); initialState[originalInputSlot] = expressionType.State; } var tempMap = PooledDictionary <BoundDagTemp, (int slot, TypeSymbol type)> .GetInstance(); Debug.Assert(originalInputSlot > 0); tempMap.Add(rootTemp, (originalInputSlot, expressionType.Type)); var nodeStateMap = PooledDictionary <BoundDecisionDagNode, (LocalState state, bool believedReachable)> .GetInstance(); nodeStateMap.Add(decisionDag.RootNode, (state: initialState.Clone(), believedReachable: true)); var labelStateMap = PooledDictionary <LabelSymbol, (LocalState state, bool believedReachable)> .GetInstance(); foreach (var dagNode in decisionDag.TopologicallySortedNodes) { bool found = nodeStateMap.TryGetValue(dagNode, out var nodeStateAndBelievedReachable); Debug.Assert(found); // the topologically sorted nodes should contain only reachable nodes (LocalState nodeState, bool nodeBelievedReachable) = nodeStateAndBelievedReachable; SetState(nodeState); switch (dagNode) { case BoundEvaluationDecisionDagNode p: { var evaluation = p.Evaluation; (int inputSlot, TypeSymbol inputType) = tempMap.TryGetValue(evaluation.Input, out var slotAndType) ? slotAndType : throw ExceptionUtilities.Unreachable; Debug.Assert(inputSlot > 0); var inputState = this.State[inputSlot]; switch (evaluation) { case BoundDagDeconstructEvaluation e: { // https://github.com/dotnet/roslyn/issues/34232 // We may need to recompute the Deconstruct method for a deconstruction if // the receiver type has changed (e.g. its nested nullability). var method = e.DeconstructMethod; int extensionExtra = method.RequiresInstanceReceiver ? 0 : 1; for (int i = 0; i < method.ParameterCount - extensionExtra; i++) { var parameterType = method.Parameters[i + extensionExtra].TypeWithAnnotations; var output = new BoundDagTemp(e.Syntax, parameterType.Type, e, i); int outputSlot = makeDagTempSlot(parameterType, output); Debug.Assert(outputSlot > 0); addToTempMap(output, outputSlot, parameterType.Type); } break; } case BoundDagTypeEvaluation e: { var output = new BoundDagTemp(e.Syntax, e.Type, e); HashSet <DiagnosticInfo> discardedDiagnostics = null; int outputSlot; switch (_conversions.WithNullability(false).ClassifyConversionFromType(inputType, e.Type, ref discardedDiagnostics).Kind) { case ConversionKind.Identity: case ConversionKind.ImplicitReference: case ConversionKind.NoConversion: case ConversionKind.ExplicitReference: outputSlot = inputSlot; break; case ConversionKind.ExplicitNullable when AreNullableAndUnderlyingTypes(inputType, e.Type, out _): outputSlot = GetNullableOfTValueSlot(inputType, inputSlot, out _, forceSlotEvenIfEmpty: true); if (outputSlot < 0) { goto default; } break; default: outputSlot = makeDagTempSlot(TypeWithAnnotations.Create(e.Type, NullableAnnotation.NotAnnotated), output); break; } State[outputSlot] = NullableFlowState.NotNull; addToTempMap(output, outputSlot, e.Type); break; } case BoundDagFieldEvaluation e: { Debug.Assert(inputSlot > 0); var field = (FieldSymbol)AsMemberOfType(inputType, e.Field); int outputSlot = GetOrCreateSlot(field, inputSlot, forceSlotEvenIfEmpty: true); Debug.Assert(outputSlot > 0); var type = field.Type; var output = new BoundDagTemp(e.Syntax, type, e); addToTempMap(output, outputSlot, type); break; } case BoundDagPropertyEvaluation e: { Debug.Assert(inputSlot > 0); var property = (PropertySymbol)AsMemberOfType(inputType, e.Property); var type = property.TypeWithAnnotations; var output = new BoundDagTemp(e.Syntax, type.Type, e); int outputSlot = GetOrCreateSlot(property, inputSlot, forceSlotEvenIfEmpty: true); if (outputSlot <= 0) { // This is needed due to https://github.com/dotnet/roslyn/issues/29619 outputSlot = makeDagTempSlot(type, output); } Debug.Assert(outputSlot > 0); addToTempMap(output, outputSlot, type.Type); break; } case BoundDagIndexEvaluation e: { var type = TypeWithAnnotations.Create(e.Property.Type, NullableAnnotation.Annotated); var output = new BoundDagTemp(e.Syntax, type.Type, e); int outputSlot = makeDagTempSlot(type, output); Debug.Assert(outputSlot > 0); addToTempMap(output, outputSlot, type.Type); break; } default: throw ExceptionUtilities.UnexpectedValue(p.Evaluation.Kind); } gotoNode(p.Next, this.State, nodeBelievedReachable); break; } case BoundTestDecisionDagNode p: { var test = p.Test; bool foundTemp = tempMap.TryGetValue(test.Input, out var slotAndType); Debug.Assert(foundTemp); (int inputSlot, TypeSymbol inputType) = slotAndType; var inputState = this.State[inputSlot]; Split(); switch (test) { case BoundDagTypeTest t: if (inputSlot > 0) { learnFromNonNullTest(inputSlot, ref this.StateWhenTrue); } gotoNode(p.WhenTrue, this.StateWhenTrue, nodeBelievedReachable); gotoNode(p.WhenFalse, this.StateWhenFalse, nodeBelievedReachable); break; case BoundDagNonNullTest t: if (inputSlot > 0) { MarkDependentSlotsNotNull(inputSlot, inputType, ref this.StateWhenFalse); if (t.IsExplicitTest) { LearnFromNullTest(inputSlot, inputType, ref this.StateWhenFalse, markDependentSlotsNotNull: false); } learnFromNonNullTest(inputSlot, ref this.StateWhenTrue); } gotoNode(p.WhenTrue, this.StateWhenTrue, nodeBelievedReachable); gotoNode(p.WhenFalse, this.StateWhenFalse, nodeBelievedReachable & inputState.MayBeNull()); break; case BoundDagExplicitNullTest t: if (inputSlot > 0) { LearnFromNullTest(inputSlot, inputType, ref this.StateWhenTrue, markDependentSlotsNotNull: true); learnFromNonNullTest(inputSlot, ref this.StateWhenFalse); } gotoNode(p.WhenTrue, this.StateWhenTrue, nodeBelievedReachable); gotoNode(p.WhenFalse, this.StateWhenFalse, nodeBelievedReachable); break; case BoundDagValueTest t: Debug.Assert(t.Value != ConstantValue.Null); if (inputSlot > 0) { learnFromNonNullTest(inputSlot, ref this.StateWhenTrue); } gotoNode(p.WhenTrue, this.StateWhenTrue, nodeBelievedReachable); gotoNode(p.WhenFalse, this.StateWhenFalse, nodeBelievedReachable); break; default: throw ExceptionUtilities.UnexpectedValue(test.Kind); } break; } case BoundLeafDecisionDagNode d: // We have one leaf decision dag node per reachable label labelStateMap.Add(d.Label, (this.State, nodeBelievedReachable)); break; case BoundWhenDecisionDagNode w: // bind the pattern variables, inferring their types as well foreach (var binding in w.Bindings) { var variableAccess = binding.VariableAccess; var tempSource = binding.TempContainingValue; var foundTemp = tempMap.TryGetValue(tempSource, out var tempSlotAndType); Debug.Assert(foundTemp); var(tempSlot, tempType) = tempSlotAndType; var tempState = this.State[tempSlot]; if (variableAccess is BoundLocal { LocalSymbol: SourceLocalSymbol local }) { var inferredType = TypeWithState.Create(tempType, tempState).ToTypeWithAnnotations(); if (_variableTypes.TryGetValue(local, out var existingType)) { // merge inferred nullable annotation from different branches of the decision tree _variableTypes[local] = TypeWithAnnotations.Create(existingType.Type, existingType.NullableAnnotation.Join(inferredType.NullableAnnotation)); } else { _variableTypes[local] = inferredType; } int localSlot = GetOrCreateSlot(local, forceSlotEvenIfEmpty: true); this.State[localSlot] = tempState; }
public void TypeMap() { var source = @" struct S<T> where T : struct { } "; var comp = CreateCompilation(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(TypeWithAnnotations.Create(typeParamType, customModifiers: customModifiers)); // NOTE: We're constructing this manually, since it's illegal. var arrayType = ArrayTypeSymbol.CreateCSharpArray(comp.Assembly, TypeWithAnnotations.Create(typeParamType, customModifiers: customModifiers)); // This is legal, but we're already manually constructing types. var typeMap = new TypeMap(ImmutableArray.Create(typeParamType), ImmutableArray.Create(TypeWithAnnotations.Create(intType))); var substitutedPointerType = (PointerTypeSymbol)typeMap.SubstituteType(pointerType).AsTypeSymbolOnly(); var substitutedArrayType = (ArrayTypeSymbol)typeMap.SubstituteType(arrayType).AsTypeSymbolOnly(); // 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.PointedAtTypeWithAnnotations.CustomModifiers); Assert.Equal(customModifiers, substitutedArrayType.ElementTypeWithAnnotations.CustomModifiers); }