Example #1
0
        // collect locals into provided scope
        // leave initializers in the tree if there are any
        public override BoundNode VisitMultipleLocalDeclarations(BoundMultipleLocalDeclarations node)
        {
            ArrayBuilder <BoundStatement> inits = null;

            foreach (var decl in node.LocalDeclarations)
            {
                var init = VisitLocalDeclaration(decl);

                if (init != null)
                {
                    if (inits == null)
                    {
                        inits = ArrayBuilder <BoundStatement> .GetInstance();
                    }

                    inits.Add((BoundStatement)init);
                }
            }

            if (inits != null)
            {
                return(BoundStatementList.Synthesized(node.Syntax, node.HasErrors, inits.ToReadOnlyAndFree()));
            }
            else
            {
                // no initializers
                return(null); // TODO: but what if hasErrors?  Have we lost that?
            }
        }
Example #2
0
            public ExpandedVarargsMethodSymbol(MethodSymbol underlyingMethod, BoundArgListOperator argList)
            {
                this.underlyingMethod = underlyingMethod;

                ArrayBuilder <ParameterSymbol> builder = ArrayBuilder <ParameterSymbol> .GetInstance();

                for (int i = 0; i < argList.Arguments.Count; ++i)
                {
                    Debug.Assert(argList.Arguments[i].Type != null);

                    builder.Add(new SynthesizedParameterSymbol(
                                    container: this,
                                    type: argList.Arguments[i].Type,
                                    ordinal: i + underlyingMethod.ParameterCount,
                                    refKind: argList.ArgumentRefKindsOpt.IsNullOrEmpty ? RefKind.None : argList.ArgumentRefKindsOpt[i],
                                    name: "")); // these fake parameters are never accessed by name.
                }

                this.extraParameters = builder.ToReadOnlyAndFree();
            }
Example #3
0
        /// <summary>
        /// Rewrites arguments of an invocation according to the receiving method. It is assumed
        /// that arguments match parameters, but may need to be expanded/reordered.
        /// </summary>
        private void RewriteArguments(
            MethodSymbol method,
            bool expanded,
            ReadOnlyArray <int> argsToParamsOpt,
            ref ReadOnlyArray <RefKind> argumentRefKinds,
            ref ReadOnlyArray <BoundExpression> rewrittenArguments,
            out ReadOnlyArray <LocalSymbol> temporaries)
        {
            // We have:
            // * a list of arguments, already converted to their proper types,
            //   in source code order. Some optional arguments might be missing.
            // * a map showing which parameter each argument corresponds to. If
            //   this is null, then the argument to parameter mapping is one-to-one.
            // * the ref kind of each argument, in source code order. That is, whether
            //   the argument was marked as ref, out, or value (neither).
            // * a method symbol.
            // * whether the call is expanded or normal form.

            // We rewrite the call so that:
            // * if in its expanded form, we create the params array.
            // * if the call requires reordering of arguments because of named arguments, temporaries are generated as needed

            // Doing this transformation can move around refness in interesting ways. For example, consider
            //
            // A().M(y : ref B()[C()], x : out D());
            //
            // This will be created as a call with receiver A(), symbol M, argument list ( B()[C()], D() ),
            // name list ( y, x ) and ref list ( ref, out ).  We can rewrite this into temporaries:
            //
            // A().M(
            //    seq ( ref int temp_y = ref B()[C()], out D() ),
            //    temp_y );
            //
            // Now we have a call with receiver A(), symbol M, argument list as shown, no name list,
            // and ref list ( out, value ). We do not want to pass a *ref* to temp_y; the temporary
            // storage is not the thing being ref'd! We want to pass the *value* of temp_y, which
            // *contains* a reference.

            // We attempt to minimize the number of temporaries required. Arguments which neither
            // produce nor observe a side effect can be placed into their proper position without
            // recourse to a temporary. For example:
            //
            // Where(predicate: x=>x.Length!=0, sequence: S())
            //
            // can be rewritten without any temporaries because the conversion from lambda to
            // delegate does not produce any side effect that could be observed by S().
            //
            // By contrast:
            //
            // Foo(z: this.p, y: this.Q(), x: (object)10)
            //
            // The boxing of 10 can be reordered, but the fetch of this.p has to happen before the
            // call to this.Q() because the call could change the value of this.p.
            //
            // We start by binding everything that is not obviously reorderable as a temporary, and
            // then run an optimizer to remove unnecessary temporaries.

            ReadOnlyArray <ParameterSymbol> parameters = method.Parameters;
            var parameterCount = parameters.Count;
            var arguments      = new BoundExpression[parameterCount];

            temporaries = ReadOnlyArray <LocalSymbol> .Null;  // not using temps by default.

            List <RefKind> refKinds = null;

            if (argumentRefKinds.IsNotNull)
            {
                refKinds = new List <RefKind>(parameterCount);
                for (int p = 0; p < parameterCount; ++p)
                {
                    refKinds.Add(RefKind.None);
                }
            }

            ArrayBuilder <BoundAssignmentOperator> storesToTemps = null;
            ArrayBuilder <BoundExpression>         paramArray    = null;

            if (expanded)
            {
                paramArray = ArrayBuilder <BoundExpression> .GetInstance();
            }

            for (int a = 0; a < rewrittenArguments.Count; ++a)
            {
                var argument = rewrittenArguments[a];
                var p        = (argsToParamsOpt.IsNotNull) ? argsToParamsOpt[a] : a;
                var refKind  = argumentRefKinds.RefKinds(a);
                Debug.Assert(arguments[p] == null);
                if (expanded && p == parameterCount - 1)
                {
                    paramArray.Add(argument);
                    Debug.Assert(refKind == RefKind.None);
                }
                else if (IsSafeForReordering(argument, refKind))
                {
                    arguments[p] = argument;
                    if (refKinds != null)
                    {
                        refKinds[p] = refKind;
                    }
                }
                else
                {
                    if (storesToTemps == null)
                    {
                        storesToTemps = ArrayBuilder <BoundAssignmentOperator> .GetInstance(rewrittenArguments.Count);
                    }

                    var tempStore = TempHelpers.StoreToTemp(argument, refKind, containingSymbol);
                    storesToTemps.Add(tempStore.Item1);
                    arguments[p] = tempStore.Item2;
                }
            }

            if (expanded)
            {
                var paramArrayType = parameters[parameterCount - 1].Type;
                var arrayArgs      = paramArray.ToReadOnlyAndFree();

                var int32Type = method.ContainingAssembly.GetPrimitiveType(Microsoft.Cci.PrimitiveTypeCode.Int32);

                arguments[parameterCount - 1] = new BoundArrayCreation(
                    null,
                    null,
                    ReadOnlyArray.Singleton <BoundExpression>(
                        new BoundLiteral(null, null, ConstantValue.Create(arrayArgs.Count), int32Type)),
                    new BoundArrayInitialization(null, null, arrayArgs),
                    paramArrayType);
            }

            for (int p = 0; p < parameterCount; ++p)
            {
                if (arguments[p] == null)
                {
                    Debug.Assert(parameters[p].IsOptional);

                    // UNDONE: Add optional arguments.
                }
            }

            if (storesToTemps != null)
            {
                int tempsNeeded = MergeArgumentsAndSideEffects(storesToTemps, arguments);

                if (tempsNeeded > 0)
                {
                    var temps = new LocalSymbol[tempsNeeded];
                    for (int i = 0, j = 0; i < storesToTemps.Count; i++)
                    {
                        var s = storesToTemps[i];
                        if (s != null)
                        {
                            temps[j++] = ((BoundLocal)s.Left).LocalSymbol;
                        }
                    }

                    temporaries = temps.AsReadOnlyWrap();
                }

                storesToTemps.Free();
            }

            // * The rewritten list of names is now null because the arguments have been reordered.
            // * The args-to-params map is now null because every argument exactly matches its parameter.
            // * The call is no longer in its expanded form.

            argumentRefKinds   = refKinds == null ? ReadOnlyArray <RefKind> .Null : refKinds.AsReadOnly <RefKind>();
            rewrittenArguments = arguments.AsReadOnlyWrap();
        }
Example #4
0
        private static BoundNode RewriteConstant(BoundExpression node)
        {
            var syntax = node.Syntax;

            Debug.Assert(node != null);
            var constantValue = node.ConstantValue;

            Debug.Assert(constantValue != null);
            Debug.Assert(node.ConstantValue.IsDecimal);

            var decimalType = node.Type as NamedTypeSymbol;

            Debug.Assert(decimalType != null);
            Debug.Assert(decimalType.SpecialType == SpecialType.System_Decimal);

            var value = node.ConstantValue.DecimalValue;
            var parts = new DecimalParts(value);
            var scale = parts.Scale;

            var          arguments = new ArrayBuilder <BoundExpression>();
            MethodSymbol ctor      = null;
            var          ctors     = decimalType.InstanceConstructors;

            // check if we can call a simple constructor
            if (scale == 0 && !parts.IsNegative && value == 0m)
            {
                // new decimal();
                foreach (MethodSymbol c in ctors)
                {
                    if (c.Parameters.Count == 0)
                    {
                        ctor = c;
                        break;
                    }
                }
            }
            else if (scale == 0 && int.MinValue <= value && value <= int.MaxValue)
            {
                //new decimal(int);
                foreach (MethodSymbol c in ctors)
                {
                    if (c.Parameters.Count == 1 && c.Parameters[0].Type.SpecialType == SpecialType.System_Int32)
                    {
                        ctor = c;
                        break;
                    }
                }
                arguments.Add(new BoundLiteral(syntax, ConstantValue.Create((int)value), ctor.Parameters[0].Type));
            }
            else if (scale == 0 && uint.MinValue <= value && value <= uint.MaxValue)
            {
                //new decimal(uint);
                foreach (MethodSymbol c in ctors)
                {
                    if (c.Parameters.Count == 1 && c.Parameters[0].Type.SpecialType == SpecialType.System_UInt32)
                    {
                        ctor = c;
                        break;
                    }
                }
                arguments.Add(new BoundLiteral(syntax, ConstantValue.Create((uint)value), ctor.Parameters[0].Type));
            }
            else if (scale == 0 && long.MinValue <= value && value <= long.MaxValue)
            {
                //new decimal(long);
                foreach (MethodSymbol c in ctors)
                {
                    if (c.Parameters.Count == 1 && c.Parameters[0].Type.SpecialType == SpecialType.System_Int64)
                    {
                        ctor = c;
                        break;
                    }
                }
                arguments.Add(new BoundLiteral(syntax, ConstantValue.Create((long)value), ctor.Parameters[0].Type));
            }
            else if (scale == 0 && ulong.MinValue <= value && value <= ulong.MaxValue)
            {
                //new decimal(ulong);
                foreach (MethodSymbol c in ctors)
                {
                    if (c.Parameters.Count == 1 && c.Parameters[0].Type.SpecialType == SpecialType.System_UInt64)
                    {
                        ctor = c;
                        break;
                    }
                }
                arguments.Add(new BoundLiteral(syntax, ConstantValue.Create((ulong)value), ctor.Parameters[0].Type));
            }
            else
            {
                //new decimal(int low, int mid, int high, bool isNegative, byte scale);
                foreach (MethodSymbol c in ctors)
                {
                    if (c.Parameters.Count == 5)
                    {
                        ctor = c;
                        break;
                    }
                }
                arguments.Add(new BoundLiteral(syntax, ConstantValue.Create(parts.Low), ctor.Parameters[0].Type));
                arguments.Add(new BoundLiteral(syntax, ConstantValue.Create(parts.Mid), ctor.Parameters[1].Type));
                arguments.Add(new BoundLiteral(syntax, ConstantValue.Create(parts.High), ctor.Parameters[2].Type));
                arguments.Add(new BoundLiteral(syntax, ConstantValue.Create(parts.IsNegative), ctor.Parameters[3].Type));
                arguments.Add(new BoundLiteral(syntax, ConstantValue.Create((byte)parts.Scale), ctor.Parameters[4].Type));
            }
            return(new BoundObjectCreationExpression(
                       node.Syntax,
                       ctor,
                       arguments.ToReadOnlyAndFree()));
        }
        private static BoundNode RewriteConstant(BoundExpression node)
        {
            var syntax = node.Syntax;

            Debug.Assert(node != null);
            var constantValue = node.ConstantValue;
            Debug.Assert(constantValue != null);
            Debug.Assert(node.ConstantValue.IsDecimal);

            var decimalType = node.Type as NamedTypeSymbol;

            Debug.Assert(decimalType != null);
            Debug.Assert(decimalType.SpecialType == SpecialType.System_Decimal);

            var value = node.ConstantValue.DecimalValue;
            var parts = new DecimalParts(value);
            var scale = parts.Scale;

            var arguments = new ArrayBuilder<BoundExpression>();
            MethodSymbol ctor = null;
            var ctors = decimalType.InstanceConstructors;

            // check if we can call a simple constructor
            if (scale == 0 && !parts.IsNegative && value == 0m)
            {
                // new decimal();
                foreach (MethodSymbol c in ctors)
                {
                    if (c.Parameters.Count == 0)
                    {
                        ctor = c;
                        break;
                    }
                }
            }
            else if (scale == 0 && int.MinValue <= value && value <= int.MaxValue)
            {
                //new decimal(int);
                foreach (MethodSymbol c in ctors)
                {
                    if (c.Parameters.Count == 1 && c.Parameters[0].Type.SpecialType == SpecialType.System_Int32)
                    {
                        ctor = c;
                        break;
                    }
                }
                arguments.Add(new BoundLiteral(syntax, ConstantValue.Create((int)value), ctor.Parameters[0].Type));
            }
            else if (scale == 0 && uint.MinValue <= value && value <= uint.MaxValue)
            {
                //new decimal(uint);
                foreach (MethodSymbol c in ctors)
                {
                    if (c.Parameters.Count == 1 && c.Parameters[0].Type.SpecialType == SpecialType.System_UInt32)
                    {
                        ctor = c;
                        break;
                    }
                }
                arguments.Add(new BoundLiteral(syntax, ConstantValue.Create((uint)value), ctor.Parameters[0].Type));
            }
            else if (scale == 0 && long.MinValue <= value && value <= long.MaxValue)
            {
                //new decimal(long);
                foreach (MethodSymbol c in ctors)
                {
                    if (c.Parameters.Count == 1 && c.Parameters[0].Type.SpecialType == SpecialType.System_Int64)
                    {
                        ctor = c;
                        break;
                    }
                }
                arguments.Add(new BoundLiteral(syntax, ConstantValue.Create((long)value), ctor.Parameters[0].Type));
            }
            else if (scale == 0 && ulong.MinValue <= value && value <= ulong.MaxValue)
            {
                //new decimal(ulong);
                foreach (MethodSymbol c in ctors)
                {
                    if (c.Parameters.Count == 1 && c.Parameters[0].Type.SpecialType == SpecialType.System_UInt64)
                    {
                        ctor = c;
                        break;
                    }
                }
                arguments.Add(new BoundLiteral(syntax, ConstantValue.Create((ulong)value), ctor.Parameters[0].Type));
            }
            else
            {
                //new decimal(int low, int mid, int high, bool isNegative, byte scale);
                foreach (MethodSymbol c in ctors)
                {
                    if (c.Parameters.Count == 5)
                    {
                        ctor = c;
                        break;
                    }
                }
                arguments.Add(new BoundLiteral(syntax, ConstantValue.Create(parts.Low), ctor.Parameters[0].Type));
                arguments.Add(new BoundLiteral(syntax, ConstantValue.Create(parts.Mid), ctor.Parameters[1].Type));
                arguments.Add(new BoundLiteral(syntax, ConstantValue.Create(parts.High), ctor.Parameters[2].Type));
                arguments.Add(new BoundLiteral(syntax, ConstantValue.Create(parts.IsNegative), ctor.Parameters[3].Type));
                arguments.Add(new BoundLiteral(syntax, ConstantValue.Create((byte)parts.Scale), ctor.Parameters[4].Type));
            }
            return new BoundObjectCreationExpression(
                node.Syntax,
                ctor,
                arguments.ToReadOnlyAndFree());
        }
        /// <summary>
        /// Resolves given metadata references to assemblies and modules.
        /// </summary>
        /// <param name="compilation">The compilation whose references are being resolved.</param>
        /// <param name="references">List where to store resolved references. References from #r directives will follow references passed to the compilation constructor.</param>
        /// <param name="boundReferenceDirectiveMap">Maps #r values to successuflly resolved metadata references. Does not contain values that failed to resolve.</param>
        /// <param name="boundReferenceDirectives">Unique metadata references resolved from #r directives.</param>
        /// <param name="assemblies">List where to store information about resolved assemblies to.</param>
        /// <param name="modules">List where to store information about resolved modules to.</param>
        /// <param name="diagnostics">Diagnostic bag where to report resolution errors.</param>
        /// <returns>
        /// Maps index to <paramref name="references"/> to an index of a resolved assembly or module in <paramref name="assemblies"/> or <paramref name="modules"/>, respectively.
        ///</returns>
        protected ReadOnlyArray <ResolvedReference> ResolveMetadataReferences(
            TCompilation compilation,
            List <MetadataReference> references,
            out IDictionary <string, MetadataReference> boundReferenceDirectiveMap,
            out ReadOnlyArray <MetadataReference> boundReferenceDirectives,
            List <AssemblyData> assemblies,
            List <Module> modules,
            DiagnosticBag diagnostics)
        {
            // Locations of all #r directives in the order they are listed in the references list.
            List <CommonLocation> referenceDirectiveLocations;

            GetCompilationReferences(compilation, diagnostics, references, out boundReferenceDirectiveMap, out referenceDirectiveLocations);

            int externalReferenceCount = compilation.ExternalReferences.Count;
            int referenceCount         = references.Count;

            // References originating from #r directives precede references supplied as arguments of the compilation.
            int referenceDirectiveCount = referenceCount - externalReferenceCount;

            Debug.Assert((referenceDirectiveLocations != null ? referenceDirectiveLocations.Count : 0) == referenceDirectiveCount);

            var referenceMap = new ResolvedReference[referenceCount];

            // Maps references that were added to the reference set (i.e. not filtered out as duplicates) to a set of names that
            // can be used to alias these references. Duplicate assemblies contribute their aliases into this set.
            Dictionary <MetadataReference, ArrayBuilder <string> > aliasMap = null;

            // Used to filter out duplicate references that reference the same file (resolve to the same full normalized path).
            var boundReferences = new Dictionary <MetadataReference, MetadataReference>(MetadataReferenceEqualityComparer.Instance);

            // Used to filter out assemblies that have the same strong or weak identity.
            // Maps simple name to a list of full names.
            Dictionary <string, List <ReferencedAssemblyIdentity> > assemblyReferencesBySimpleName = null;

            ArrayBuilder <MetadataReference> uniqueDirectiveReferences = (referenceDirectiveLocations != null) ? ArrayBuilder <MetadataReference> .GetInstance() : null;

            // When duplicate references with conflicting EmbedInteropTypes flag are encountered,
            // VB uses the flag from the last one, C# reports an error. We need to enumerate in reverse order
            // so that we find the one that matters first.
            for (int referenceIndex = referenceCount - 1; referenceIndex >= 0; referenceIndex--)
            {
                var boundReference = references[referenceIndex];
                if (boundReference == null)
                {
                    continue;
                }

                // add bound reference if it doesn't exist yet, merging aliases:
                MetadataReference existingReference;
                if (boundReferences.TryGetValue(boundReference, out existingReference))
                {
                    if (CheckPropertiesConsistency(boundReference, existingReference, diagnostics))
                    {
                        AddAlias(existingReference, boundReference.Properties.Alias, ref aliasMap);
                    }

                    continue;
                }

                boundReferences.Add(boundReference, boundReference);

                CommonLocation location;
                if (referenceIndex < referenceDirectiveCount)
                {
                    location = referenceDirectiveLocations[referenceIndex];
                    uniqueDirectiveReferences.Add(boundReference);
                }
                else
                {
                    location = MessageProvider.NoLocation;
                }

                // compilation reference

                var compilationReference = boundReference as CommonCompilationReference;
                if (compilationReference != null)
                {
                    switch (compilationReference.Properties.Kind)
                    {
                    case MetadataImageKind.Assembly:
                        existingReference = TryAddAssembly(compilationReference.Compilation.Assembly.Identity, boundReference, diagnostics, location, ref assemblyReferencesBySimpleName);
                        if (existingReference != null)
                        {
                            AddAlias(existingReference, boundReference.Properties.Alias, ref aliasMap);
                            continue;
                        }

                        // Note, if SourceAssemblySymbol hasn't been created for
                        // compilationAssembly.Compilation yet, we want this to happen
                        // right now. Conveniently, this constructor will trigger creation of the
                        // SourceAssemblySymbol.
                        var asmData = CreateAssemblyDataForCompilation(compilationReference);
                        AddAssembly(asmData, referenceIndex, assemblies, referenceMap);
                        break;

                    default:
                        throw Contract.Unreachable;
                    }

                    continue;
                }

                // PE reference

                var      peReference = (PortableExecutableReference)boundReference;
                Metadata metadata    = peReference.GetMetadata(MessageProvider, location, diagnostics);
                Debug.Assert(metadata != null || diagnostics.HasAnyErrors());

                if (metadata != null)
                {
                    Debug.Assert(metadata != null);

                    switch (peReference.Properties.Kind)
                    {
                    case MetadataImageKind.Assembly:
                        var assemblyMetadata = (AssemblyMetadata)metadata;
                        WeakList <IAssemblySymbol> cachedSymbols = assemblyMetadata.CachedSymbols;

                        if (assemblyMetadata.IsValidAssembly())
                        {
                            Assembly assembly = assemblyMetadata.Assembly;
                            existingReference = TryAddAssembly(assembly.Identity, peReference, diagnostics, location, ref assemblyReferencesBySimpleName);
                            if (existingReference != null)
                            {
                                AddAlias(existingReference, boundReference.Properties.Alias, ref aliasMap);
                                continue;
                            }

                            var asmData = CreateAssemblyDataForFile(
                                assembly,
                                cachedSymbols,
                                peReference.GetDocumentationProvider(),
                                SimpleAssemblyName,
                                compilation.Options.AlwaysImportInternalMembers,
                                peReference.Properties.EmbedInteropTypes);

                            AddAssembly(asmData, referenceIndex, assemblies, referenceMap);
                        }
                        else
                        {
                            diagnostics.Add(MessageProvider.CreateDiagnostic(MessageProvider.ERR_MetadataFileNotAssembly, location, peReference.Display));
                        }

                        // asmData keeps strong ref after this point
                        GC.KeepAlive(assemblyMetadata);
                        break;

                    case MetadataImageKind.Module:
                        var moduleMetadata = (ModuleMetadata)metadata;
                        if (moduleMetadata.IsValidModule())
                        {
                            AddModule(moduleMetadata.Module, referenceIndex, modules, referenceMap);
                        }
                        else
                        {
                            diagnostics.Add(MessageProvider.CreateDiagnostic(MessageProvider.ERR_MetadataFileNotModule, location, peReference.Display));
                        }
                        break;

                    default:
                        throw Contract.Unreachable;
                    }
                }
            }

            if (uniqueDirectiveReferences != null)
            {
                uniqueDirectiveReferences.Reverse();
                boundReferenceDirectives = uniqueDirectiveReferences.ToReadOnlyAndFree();
            }
            else
            {
                boundReferenceDirectives = ReadOnlyArray <MetadataReference> .Empty;
            }

            for (int i = 0; i < referenceMap.Length; i++)
            {
                if (!referenceMap[i].IsSkipped)
                {
                    int reversedIndex = (referenceMap[i].Kind == MetadataImageKind.Assembly ? assemblies.Count : modules.Count) - 1 - referenceMap[i].Index;
                    referenceMap[i] = new ResolvedReference(reversedIndex, referenceMap[i].Kind, GetAliases(references[i], aliasMap));
                }
            }

            assemblies.Reverse();
            modules.Reverse();
            return(referenceMap.AsReadOnlyWrap());
        }