// 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? } }
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(); }
/// <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(); }
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()); }