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);
        }
Example #3
0
        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
            });
        }
Example #4
0
 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;
        }
Example #6
0
        // NOTE: Specifically not overriding IsIndirectlyInIterator.

        internal override TypeWithAnnotations GetIteratorElementType()
        {
            return(TypeWithAnnotations.Create(CreateErrorType()));
        }
Example #7
0
        /// <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));
            }
        }
Example #13
0
        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);
        }
Example #14
0
        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());
        }
Example #15
0
        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);
        }
Example #16
0
        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);
            }
        }
Example #17
0
        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));
        }
Example #18
0
 private static bool CanUnifyHelper(TypeSymbol t1, TypeSymbol t2, ref MutableTypeMap substitution)
 {
     return(CanUnifyHelper(TypeWithAnnotations.Create(t1), TypeWithAnnotations.Create(t2), ref substitution));
 }
Example #19
0
        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;
            }
        }
Example #20
0
        /// <summary>
        /// Determine whether there is any substitution of type parameters that will
        /// make two types identical.
        /// </summary>
        /// <param name="t1">LHS</param>
        /// <param name="t2">RHS</param>
        /// <param name="substitution">
        /// Substitutions performed so far (or null for none).
        /// Keys are type parameters, values are types (possibly type parameters).
        /// Will be updated with new substitutions by the callee.
        /// Should be ignored when false is returned.
        /// </param>
        /// <returns>True if there exists a type map such that Map(LHS) == Map(RHS).</returns>
        /// <remarks>
        /// Derived from Dev10's BSYMMGR::UnifyTypes.
        /// Two types will not unify if they have different custom modifiers.
        /// </remarks>
        private static bool CanUnifyHelper(TypeWithAnnotations t1, TypeWithAnnotations t2, ref MutableTypeMap substitution)
        {
            if (!t1.HasType || !t2.HasType)
            {
                return(t1.IsSameAs(t2));
            }

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

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

            // If one of the types is a type parameter, then the substitution could make them equal.
            if (TypeSymbol.Equals(t1.Type, t2.Type, TypeCompareKind.ConsiderEverything2) && t1.CustomModifiers.SequenceEqual(t2.CustomModifiers))
            {
                return(true);
            }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

                int arity = nt1.Arity;

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

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

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

                // Note: Dev10 folds this into the loop since GetTypeArgsAll includes type args for containing types
                // TODO: Calling CanUnifyHelper for the containing type is an overkill, we simply need to go through type arguments for all containers.
                return((object)nt1.ContainingType == null || CanUnifyHelper(nt1.ContainingType, nt2.ContainingType, ref substitution));
            }

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

                TypeParameterSymbol tp1 = (TypeParameterSymbol)t1.Type;

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

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

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

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

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

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

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

                return(false);
            }

            default:
            {
                return(false);
            }
            }
        }
Example #21
0
        /// <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,
Example #22
0
 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);
            }
        }
Example #24
0
 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);
            }
Example #28
0
        /// <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;
                        }
Example #30
0
        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);
        }