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 HashSet <string> uniqueFieldNames = new HashSet <string>(); 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 { nameToken = expression.ExtractAnonymousTypeMemberName(); } hasError = hasError || expression.HasErrors; boundExpressions[i] = this.BindValue(expression, diagnostics, BindValueKind.RValue); // check the name to be unique string fieldName = null; if (nameToken.Kind() == SyntaxKind.IdentifierToken) { fieldName = nameToken.ValueText; if (uniqueFieldNames.Contains(fieldName)) { // name duplication Error(diagnostics, ErrorCode.ERR_AnonymousTypeDuplicatePropertyName, fieldInitializer); hasError = true; fieldName = null; } else { uniqueFieldNames.Add(fieldName); } } 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, fieldType); // NOTE: ERR_InvalidAnonymousTypeMemberDeclarator (CS0746) would be generated by parser if needed } // 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 override Symbol VisitNamedType(NamedTypeSymbol sourceType) { var originalDef = sourceType.OriginalDefinition; if ((object)originalDef != (object)sourceType) { HashSet <DiagnosticInfo> useSiteDiagnostics = null; var typeArguments = sourceType.GetAllTypeArguments(ref useSiteDiagnostics); var otherDef = (NamedTypeSymbol)Visit(originalDef); if (otherDef is null) { return(null); } var otherTypeParameters = otherDef.GetAllTypeParameters(); bool translationFailed = false; var otherTypeArguments = typeArguments.SelectAsArray((t, v) => { var newType = (TypeSymbol)v.Visit(t.Type); if (newType is null) { // For a newly added type, there is no match in the previous generation, so it could be null. translationFailed = true; newType = t.Type; } return(t.WithTypeAndModifiers(newType, v.VisitCustomModifiers(t.CustomModifiers))); }, this); if (translationFailed) { // For a newly added type, there is no match in the previous generation, so it could be null. return(null); } // TODO: LambdaFrame has alpha renamed type parameters, should we rather fix that? var typeMap = new TypeMap(otherTypeParameters, otherTypeArguments, allowAlpha: true); return(typeMap.SubstituteNamedType(otherDef)); } Debug.Assert(sourceType.IsDefinition); var otherContainer = this.Visit(sourceType.ContainingSymbol); // Containing type will be missing from other assembly // if the type was added in the (newer) source assembly. if (otherContainer is null) { return(null); } switch (otherContainer.Kind) { case SymbolKind.Namespace: if (sourceType is AnonymousTypeManager.AnonymousTypeTemplateSymbol template) { Debug.Assert((object)otherContainer == (object)_otherAssembly.GlobalNamespace); TryFindAnonymousType(template, out var value); return((NamedTypeSymbol)value.Type); } if (sourceType.IsAnonymousType) { return(Visit(AnonymousTypeManager.TranslateAnonymousTypeSymbol(sourceType))); } return(FindMatchingMember(otherContainer, sourceType, AreNamedTypesEqual)); case SymbolKind.NamedType: return(FindMatchingMember(otherContainer, sourceType, AreNamedTypesEqual)); default: throw ExceptionUtilities.UnexpectedValue(otherContainer.Kind); } }
public override Symbol VisitNamedType(NamedTypeSymbol sourceType) { var originalDef = sourceType.OriginalDefinition; if ((object)originalDef != (object)sourceType) { HashSet <DiagnosticInfo> useSiteDiagnostics = null; var typeArguments = sourceType.GetAllTypeArguments(ref useSiteDiagnostics); var otherDef = (NamedTypeSymbol)this.Visit(originalDef); if ((object)otherDef == null) { return(null); } var otherTypeParameters = otherDef.GetAllTypeParameters(); var otherTypeArguments = typeArguments.SelectAsArray((t, v) => (TypeSymbol)v.Visit(t), this); Debug.Assert(otherTypeArguments.All(t => (object)t != null)); // TODO: LambdaFrame has alpha renamed type parameters, should we rather fix that? var typeMap = new TypeMap(otherTypeParameters, otherTypeArguments, allowAlpha: true); return(typeMap.SubstituteNamedType(otherDef)); } Debug.Assert(sourceType.IsDefinition); var otherContainer = this.Visit(sourceType.ContainingSymbol); // Containing type will be missing from other assembly // if the type was added in the (newer) source assembly. if ((object)otherContainer == null) { return(null); } switch (otherContainer.Kind) { case SymbolKind.Namespace: if (AnonymousTypeManager.IsAnonymousTypeTemplate(sourceType)) { Debug.Assert((object)otherContainer == (object)this.otherAssembly.GlobalNamespace); AnonymousTypeValue value; this.TryFindAnonymousType(sourceType, out value); return((NamedTypeSymbol)value.Type); } else if (sourceType.IsAnonymousType) { return(this.Visit(AnonymousTypeManager.TranslateAnonymousTypeSymbol(sourceType))); } else { return(FindMatchingNamespaceMember((NamespaceSymbol)otherContainer, sourceType, AreNamedTypesEqual)); } case SymbolKind.NamedType: return(FindMatchingNamedTypeMember((NamedTypeSymbol)otherContainer, sourceType, AreNamedTypesEqual)); default: throw ExceptionUtilities.UnexpectedValue(otherContainer.Kind); } }
private BoundExpression BindCodeblock(SyntaxNode syntax, UnboundLambda unboundLambda, Conversion conversion, bool isCast, TypeSymbol destination, DiagnosticBag diagnostics) { if (!Compilation.Options.HasRuntime) { return(null); } var isCodeblock = syntax.XIsCodeBlock; if (!isCodeblock) { isCodeblock = !destination.IsDelegateType() && !destination.IsExpressionTree(); } if (!isCodeblock) { return(null); } Conversion conv = Conversion.ImplicitReference; if (destination != Compilation.CodeBlockType() && !destination.IsObjectType()) { HashSet <DiagnosticInfo> useSiteDiagnostics = null; conv = Conversions.ClassifyConversionFromType(Compilation.CodeBlockType(), destination, ref useSiteDiagnostics); diagnostics.Add(syntax, useSiteDiagnostics); } if (Compilation.Options.HasRuntime) { Debug.Assert(destination == Compilation.CodeBlockType() || conv.Exists); } if (!syntax.XIsCodeBlock && !Compilation.Options.MacroScript && !syntax.XNode.IsAliasExpression()) { Error(diagnostics, ErrorCode.ERR_CodeblockWithLambdaSyntax, syntax); } AnonymousTypeManager manager = this.Compilation.AnonymousTypeManager; var delegateSignature = new TypeSymbol[unboundLambda.ParameterCount + 1]; var usualType = this.Compilation.UsualType(); for (int i = 0; i < delegateSignature.Length; i++) { delegateSignature[i] = usualType; } NamedTypeSymbol cbType = manager.ConstructCodeblockTypeSymbol(delegateSignature, syntax.Location); var delType = manager.GetCodeblockDelegateType(cbType); var _boundLambda = unboundLambda.Bind(delType); diagnostics.AddRange(_boundLambda.Diagnostics); var cbDel = new BoundConversion( syntax, _boundLambda, conversion, @checked: false, explicitCastInCode: false, constantValueOpt: ConstantValue.NotAvailable, type: delType) { WasCompilerGenerated = unboundLambda.WasCompilerGenerated }; var cbSrc = new BoundLiteral(syntax, ConstantValue.Create(syntax.XCodeBlockSource), Compilation.GetSpecialType(SpecialType.System_String)); BoundExpression cbInst = new BoundAnonymousObjectCreationExpression(syntax, cbType.InstanceConstructors[0], new BoundExpression[] { cbDel, cbSrc }.ToImmutableArrayOrEmpty(), System.Collections.Immutable.ImmutableArray <BoundAnonymousPropertyDeclaration> .Empty, cbType) { WasCompilerGenerated = unboundLambda.WasCompilerGenerated };; if (conv != Conversion.ImplicitReference) { cbInst = new BoundConversion(syntax, cbInst, Conversion.ImplicitReference, false, false, ConstantValue.NotAvailable, Compilation.CodeBlockType()) { WasCompilerGenerated = unboundLambda.WasCompilerGenerated };; } if (!conv.IsValid || (!isCast && conv.IsExplicit)) { GenerateImplicitConversionError(diagnostics, syntax, conv, cbInst, destination); return(new BoundConversion( syntax, cbInst, conv, false, explicitCastInCode: isCast, constantValueOpt: ConstantValue.NotAvailable, type: destination, hasErrors: true) { WasCompilerGenerated = unboundLambda.WasCompilerGenerated }); } return(new BoundConversion( syntax, cbInst, conv, false, explicitCastInCode: isCast, constantValueOpt: ConstantValue.NotAvailable, type: destination) { WasCompilerGenerated = unboundLambda.WasCompilerGenerated }); }
private PhpCompilation( string assemblyName, PhpCompilationOptions options, ImmutableArray<MetadataReference> references, //ReferenceManager referenceManager, //SyntaxAndDeclarationManager syntaxAndDeclarations AsyncQueue<CompilationEvent> eventQueue = null ) : base(assemblyName, references, SyntaxTreeCommonFeatures(ImmutableArray<SyntaxTree>.Empty), false, eventQueue) { _wellKnownMemberSignatureComparer = new WellKnownMembersSignatureComparer(this); _options = options; _referenceManager = new ReferenceManager(options.SdkDirectory); _tables = new SourceDeclarations(); _coreTypes = new CoreTypes(this); _coreMethods = new CoreMethods(_coreTypes); _anonymousTypeManager = new AnonymousTypeManager(this); }
private void CompileNamedType(NamedTypeSymbol symbol) { TypeCompilationState compilationState = new TypeCompilationState(symbol, moduleBeingBuilt); cancellationToken.ThrowIfCancellationRequested(); // Find the constructor of a script class. MethodSymbol scriptCtor = null; if (symbol.IsScriptClass) { // The field initializers of a script class could be arbitrary statements, // including blocks. Field initializers containing blocks need to // use a MethodBodySemanticModel to build up the appropriate tree of binders, and // MethodBodySemanticModel requires an "owning" method. That's why we're digging out // the constructor - it will own the field initializers. scriptCtor = symbol.InstanceConstructors[0]; Debug.Assert((object)scriptCtor != null); } var synthesizedSubmissionFields = symbol.IsSubmissionClass ? new SynthesizedSubmissionFields(compilation, symbol) : null; var processedStaticInitializers = new ProcessedFieldInitializers(); var processedInstanceInitializers = new ProcessedFieldInitializers(); var sourceTypeSymbol = symbol as SourceMemberContainerTypeSymbol; if ((object)sourceTypeSymbol != null) { BindFieldInitializers(sourceTypeSymbol, scriptCtor, sourceTypeSymbol.StaticInitializers, this.generateDebugInfo, ref processedStaticInitializers); BindFieldInitializers(sourceTypeSymbol, scriptCtor, sourceTypeSymbol.InstanceInitializers, this.generateDebugInfo, ref processedInstanceInitializers); if (compilationState.Emitting) { CompileSynthesizedExplicitImplementations(sourceTypeSymbol, compilationState); } } // Indicates if a static constructor is in the member, // so we can decide to synthesize a static constructor. bool hasStaticConstructor = false; foreach (var member in symbol.GetMembers()) { //When a filter is supplied, limit the compilation of members passing the filter. if ((this.filter != null) && !this.filter(member)) { continue; } switch (member.Kind) { case SymbolKind.NamedType: member.Accept(this, compilationState); break; case SymbolKind.Method: { MethodSymbol method = (MethodSymbol)member; if (method.IsSubmissionConstructor || IsFieldLikeEventAccessor(method)) { continue; } if (method.IsPartial()) { method = method.PartialImplementation(); if ((object)method == null) { continue; } } ProcessedFieldInitializers processedInitializers = method.MethodKind == MethodKind.Constructor ? processedInstanceInitializers : method.MethodKind == MethodKind.StaticConstructor ? processedStaticInitializers : default(ProcessedFieldInitializers); CompileMethod(method, ref processedInitializers, synthesizedSubmissionFields, compilationState); // Set a flag to indicate that a static constructor is created. if (method.MethodKind == MethodKind.StaticConstructor) { hasStaticConstructor = true; } break; } case SymbolKind.Property: { SourcePropertySymbol sourceProperty = member as SourcePropertySymbol; if ((object)sourceProperty != null && sourceProperty.IsSealed && compilationState.Emitting) { CompileSynthesizedSealedAccessors(sourceProperty, compilationState); } break; } case SymbolKind.Event: { SourceEventSymbol eventSymbol = member as SourceEventSymbol; if ((object)eventSymbol != null && eventSymbol.HasAssociatedField && !eventSymbol.IsAbstract && compilationState.Emitting) { CompileFieldLikeEventAccessor(eventSymbol, isAddMethod: true, compilationState: compilationState); CompileFieldLikeEventAccessor(eventSymbol, isAddMethod: false, compilationState: compilationState); } break; } case SymbolKind.Field: { SourceMemberFieldSymbol fieldSymbol = member as SourceMemberFieldSymbol; if ((object)fieldSymbol != null) { if (fieldSymbol.IsConst) { // We check specifically for constant fields with bad values because they never result // in bound nodes being inserted into method bodies (in which case, they would be covered // by the method-level check). ConstantValue constantValue = fieldSymbol.GetConstantValue(ConstantFieldsInProgress.Empty, earlyDecodingWellKnownAttributes: false); SetGlobalErrorIfTrue(constantValue == null || constantValue.IsBad); } if (fieldSymbol.IsFixed && compilationState.Emitting) { // force the generation of implementation types for fixed-size buffers TypeSymbol discarded = fieldSymbol.FixedImplementationType(compilationState.ModuleBuilder); } } break; } } } Debug.Assert(symbol.TypeKind != TypeKind.Submission || ((object)scriptCtor != null && scriptCtor.IsSubmissionConstructor)); // process additional anonymous type members if (AnonymousTypeManager.IsAnonymousTypeTemplate(symbol)) { ProcessedFieldInitializers processedInitializers = default(ProcessedFieldInitializers); foreach (var method in AnonymousTypeManager.GetAnonymousTypeHiddenMethods(symbol)) { CompileMethod(method, ref processedInitializers, synthesizedSubmissionFields, compilationState); } } // In the case there are field initializers but we haven't created an implicit static constructor (.cctor) for it, // (since we may not add .cctor implicitly created for decimals into the symbol table) // it is necessary for the compiler to generate the static constructor here if we are emitting. if (moduleBeingBuilt != null && !hasStaticConstructor && !processedStaticInitializers.BoundInitializers.IsDefaultOrEmpty) { Debug.Assert(processedStaticInitializers.BoundInitializers.All((init) => (init.Kind == BoundKind.FieldInitializer) && !((BoundFieldInitializer)init).Field.IsMetadataConstant)); MethodSymbol method = new SynthesizedStaticConstructor(sourceTypeSymbol); if ((this.filter == null) || this.filter(method)) { CompileMethod(method, ref processedStaticInitializers, synthesizedSubmissionFields, compilationState); // If this method has been successfully built, we emit it. if (moduleBeingBuilt.GetMethodBody(method) != null) { moduleBeingBuilt.AddCompilerGeneratedDefinition(sourceTypeSymbol, method); } } } // compile submission constructor last so that synthesized submission fields are collected from all script methods: if (synthesizedSubmissionFields != null && compilationState.Emitting) { Debug.Assert(scriptCtor.IsSubmissionConstructor); CompileMethod(scriptCtor, ref processedInstanceInitializers, synthesizedSubmissionFields, compilationState); synthesizedSubmissionFields.AddToType(scriptCtor.ContainingType, compilationState.ModuleBuilder); } // Emit synthesized methods produced during lowering if any CompileGeneratedMethods(compilationState); compilationState.Free(); }
public void BuildType_EmptyPropertyCollection_ThrowsException() { Assert.That(() => AnonymousTypeManager.BuildType(Enumerable.Empty <Property>()), Throws.ArgumentException); }
public void BuildType_NullPropertyCollection_ThrowsException() { Assert.That(() => AnonymousTypeManager.BuildType(null), Throws.InstanceOf <ArgumentNullException>()); }