internal RangeVariableSymbol AddRangeVariable(Binder binder, SyntaxToken identifier, DiagnosticBag diagnostics) { string name = identifier.ValueText; var result = new RangeVariableSymbol(name, binder.ContainingMemberOrLambda, identifier.GetLocation()); bool error = false; foreach (var existingRangeVariable in allRangeVariables.Keys) { #if XSHARP if (XSharpString.Equals(existingRangeVariable.Name, name)) #else if (existingRangeVariable.Name == name) #endif { diagnostics.Add(ErrorCode.ERR_QueryDuplicateRangeVariable, identifier.GetLocation(), name); error = true; } } if (!error) { var collisionDetector = new LocalScopeBinder(binder); collisionDetector.ValidateDeclarationNameConflictsInScope(result, diagnostics); } allRangeVariables.Add(result, ArrayBuilder <string> .GetInstance()); return(result); }
private UnboundLambda BindAnonymousFunction(CSharpSyntaxNode syntax, DiagnosticBag diagnostics) { Debug.Assert(syntax != null); Debug.Assert(syntax.IsAnonymousFunction()); var results = AnalyzeAnonymousFunction(syntax, diagnostics); var refKinds = results.Item1; var types = results.Item2; var names = results.Item3; var isAsync = results.Item4; if (!types.IsDefault) { foreach (var type in types) { // UNDONE: Where do we report improper use of pointer types? if ((object)type != null && type.IsStatic) { Error(diagnostics, ErrorCode.ERR_ParameterIsStaticClass, syntax, type); } } } var lambda = new UnboundLambda(syntax, this, refKinds, types, names, isAsync); if (!names.IsDefault) { var binder = new LocalScopeBinder(this); var pNames = PooledHashSet <string> .GetInstance(); for (int i = 0; i < lambda.ParameterCount; i++) { var name = lambda.ParameterName(i); if (string.IsNullOrEmpty(name)) { continue; } if (pNames.Contains(name)) { // The parameter name '{0}' is a duplicate diagnostics.Add(ErrorCode.ERR_DuplicateParamName, lambda.ParameterLocation(i), name); } else { pNames.Add(name); binder.ValidateLambdaParameterNameConflictsInScope(lambda.ParameterLocation(i), name, diagnostics); } } pNames.Free(); } return(lambda); }
/// <summary> /// In regular C#, all field initializers are assignments to fields and the assigned expressions /// may not reference instance members. /// </summary> private static void BindRegularCSharpFieldInitializers( CSharpCompilation compilation, ImmutableArray <ImmutableArray <FieldOrPropertyInitializer> > initializers, ArrayBuilder <BoundInitializer> boundInitializers, DiagnosticBag diagnostics, bool generateDebugInfo, out ImportChain firstDebugImports) { firstDebugImports = null; foreach (ImmutableArray <FieldOrPropertyInitializer> siblingInitializers in initializers) { // All sibling initializers share the same parent node and tree so we can reuse the binder // factory across siblings. Unfortunately, we cannot reuse the binder itself, because // individual fields might have their own binders (e.g. because of being declared unsafe). BinderFactory binderFactory = null; foreach (FieldOrPropertyInitializer initializer in siblingInitializers) { FieldSymbol fieldSymbol = initializer.FieldOpt; Debug.Assert((object)fieldSymbol != null); // A constant field of type decimal needs a field initializer, so // check if it is a metadata constant, not just a constant to exclude // decimals. Other constants do not need field initializers. if (!fieldSymbol.IsMetadataConstant) { //Can't assert that this is a regular C# compilation, because we could be in a nested type of a script class. SyntaxReference syntaxRef = initializer.Syntax; var initializerNode = (EqualsValueClauseSyntax)syntaxRef.GetSyntax(); if (binderFactory == null) { binderFactory = compilation.GetBinderFactory(syntaxRef.SyntaxTree); } Binder parentBinder = binderFactory.GetBinder(initializerNode); Debug.Assert(parentBinder.ContainingMemberOrLambda == fieldSymbol.ContainingType || //should be the binder for the type fieldSymbol.ContainingType.IsImplicitClass); //however, we also allow fields in namespaces to help support script scenarios if (generateDebugInfo && firstDebugImports == null) { firstDebugImports = parentBinder.ImportChain; } parentBinder = new LocalScopeBinder(parentBinder).WithAdditionalFlagsAndContainingMemberOrLambda(parentBinder.Flags | BinderFlags.FieldInitializer, fieldSymbol); BoundFieldInitializer boundInitializer = BindFieldInitializer(parentBinder, fieldSymbol, initializerNode, diagnostics); boundInitializers.Add(boundInitializer); } } } }
private static ImmutableArray <LabelSymbol> GetLabels(SynthesizedInteractiveInitializerMethod scriptInitializer, CompilationUnitSyntax syntax) { var builder = ArrayBuilder <LabelSymbol> .GetInstance(); foreach (var member in syntax.Members) { if (member.Kind() != SyntaxKind.GlobalStatement) { continue; } LocalScopeBinder.BuildLabels(scriptInitializer, ((GlobalStatementSyntax)member).Statement, ref builder); } return(builder.ToImmutableAndFree()); }
private UnboundLambda BindAnonymousFunction(CSharpSyntaxNode syntax, DiagnosticBag diagnostics) { Debug.Assert(syntax != null); Debug.Assert(syntax.IsAnonymousFunction()); var(refKinds, types, names, isAsync) = AnalyzeAnonymousFunction(syntax, diagnostics); if (!types.IsDefault) { foreach (var type in types) { // UNDONE: Where do we report improper use of pointer types? if (type.HasType && type.IsStatic) { Error(diagnostics, ErrorCode.ERR_ParameterIsStaticClass, syntax, type.Type); } } } var lambda = new UnboundLambda(syntax, this, refKinds, types, names, isAsync); if (!names.IsDefault) { var binder = new LocalScopeBinder(this); bool allowShadowingNames = binder.Compilation.IsFeatureEnabled(MessageID.IDS_FeatureNameShadowingInNestedFunctions); var pNames = PooledHashSet <string> .GetInstance(); for (int i = 0; i < lambda.ParameterCount; i++) { var name = lambda.ParameterName(i); if (string.IsNullOrEmpty(name)) { continue; } if (!pNames.Add(name)) { // The parameter name '{0}' is a duplicate diagnostics.Add(ErrorCode.ERR_DuplicateParamName, lambda.ParameterLocation(i), name); } else if (!allowShadowingNames) { binder.ValidateLambdaParameterNameConflictsInScope(lambda.ParameterLocation(i), name, diagnostics); } } pNames.Free(); } return(lambda); }
private UnboundLambda BindAnonymousFunction(CSharpSyntaxNode syntax, DiagnosticBag diagnostics) { Debug.Assert(syntax != null); Debug.Assert(syntax.IsAnonymousFunction()); var results = AnalyzeAnonymousFunction(syntax, diagnostics); var refKinds = results.Item1; var types = results.Item2; var names = results.Item3; var isAsync = results.Item4; if (!types.IsDefault) { foreach (var type in types) { // UNDONE: Where do we report improper use of pointer types? if ((object)type != null && type.IsStatic) { Error(diagnostics, ErrorCode.ERR_ParameterIsStaticClass, syntax, type); } } } var lambda = new UnboundLambda(syntax, this, refKinds, types, names, isAsync); if (!names.IsDefault) { var binder = new LocalScopeBinder(this.ContainingMemberOrLambda as MethodSymbol, this); for (int n = 0; n < names.Length; ++n) { string name = lambda.ParameterName(n); binder.ValidateLambdaParameterNameConflictsInScope(lambda.ParameterLocation(n), name, diagnostics); } } return(lambda); }
private static BoundFieldInitializer BindFieldInitializer(Binder binder, FieldSymbol fieldSymbol, EqualsValueClauseSyntax equalsValueClauseNode, DiagnosticBag diagnostics) { Debug.Assert(!fieldSymbol.IsMetadataConstant); var fieldsBeingBound = binder.FieldsBeingBound; var sourceField = fieldSymbol as SourceMemberFieldSymbol; bool isImplicitlyTypedField = (object)sourceField != null && sourceField.FieldTypeInferred(fieldsBeingBound); // If the type is implicitly typed, the initializer diagnostics have already been reported, so ignore them here: // CONSIDER (tomat): reusing the bound field initializers for implicitly typed fields. DiagnosticBag initializerDiagnostics; if (isImplicitlyTypedField) { initializerDiagnostics = DiagnosticBag.GetInstance(); } else { initializerDiagnostics = diagnostics; } var collisionDetector = new LocalScopeBinder(binder); var boundInitValue = collisionDetector.BindVariableOrAutoPropInitializer(equalsValueClauseNode, fieldSymbol.GetFieldType(fieldsBeingBound), initializerDiagnostics); if (isImplicitlyTypedField) { initializerDiagnostics.Free(); } return(new BoundFieldInitializer( equalsValueClauseNode.Value, //we want the attached sequence point to indicate the value node fieldSymbol, boundInitValue)); }
/// <summary> /// In script C#, some field initializers are assignments to fields and others are global /// statements. There are no restrictions on accessing instance members. /// </summary> private static void BindScriptFieldInitializers(CSharpCompilation compilation, MethodSymbol scriptCtor, ImmutableArray <ImmutableArray <FieldOrPropertyInitializer> > initializers, ArrayBuilder <BoundInitializer> boundInitializers, DiagnosticBag diagnostics, out ImportChain firstDebugImports) { Debug.Assert((object)scriptCtor != null); firstDebugImports = null; for (int i = 0; i < initializers.Length; i++) { ImmutableArray <FieldOrPropertyInitializer> siblingInitializers = initializers[i]; // All sibling initializers share the same parent node and tree so we can reuse the binder // factory across siblings. Unfortunately, we cannot reuse the binder itself, because // individual fields might have their own binders (e.g. because of being declared unsafe). BinderFactory binderFactory = null; for (int j = 0; j < siblingInitializers.Length; j++) { var initializer = siblingInitializers[j]; var fieldSymbol = initializer.FieldOpt; if ((object)fieldSymbol != null && fieldSymbol.IsConst) { // Constants do not need field initializers. continue; } var syntaxRef = initializer.Syntax; Debug.Assert(syntaxRef.SyntaxTree.Options.Kind != SourceCodeKind.Regular); var initializerNode = (CSharpSyntaxNode)syntaxRef.GetSyntax(); if (binderFactory == null) { binderFactory = compilation.GetBinderFactory(syntaxRef.SyntaxTree); } Binder scriptClassBinder = binderFactory.GetBinder(initializerNode); Debug.Assert(((ImplicitNamedTypeSymbol)scriptClassBinder.ContainingMemberOrLambda).IsScriptClass); if (firstDebugImports == null) { firstDebugImports = scriptClassBinder.ImportChain; } Binder parentBinder = new ExecutableCodeBinder((CSharpSyntaxNode)syntaxRef.SyntaxTree.GetRoot(), scriptCtor, scriptClassBinder); BoundInitializer boundInitializer; if ((object)fieldSymbol != null) { boundInitializer = BindFieldInitializer( new LocalScopeBinder(parentBinder).WithAdditionalFlagsAndContainingMemberOrLambda(parentBinder.Flags | BinderFlags.FieldInitializer, fieldSymbol), fieldSymbol, (EqualsValueClauseSyntax)initializerNode, diagnostics); } else if (initializerNode.Kind() == SyntaxKind.LabeledStatement) { // TODO: labels in interactive var boundStatement = new BoundBadStatement(initializerNode, ImmutableArray <BoundNode> .Empty, true); boundInitializer = new BoundGlobalStatementInitializer(initializerNode, boundStatement); } else { var collisionDetector = new LocalScopeBinder(parentBinder); boundInitializer = BindGlobalStatement(collisionDetector, (StatementSyntax)initializerNode, diagnostics, isLast: i == initializers.Length - 1 && j == siblingInitializers.Length - 1); } boundInitializers.Add(boundInitializer); } } }
/// <summary> /// In regular C#, all field initializers are assignments to fields and the assigned expressions /// may not reference instance members. /// </summary> internal static void BindRegularCSharpFieldInitializers( CSharpCompilation compilation, ImmutableArray <ImmutableArray <FieldOrPropertyInitializer> > initializers, ArrayBuilder <BoundInitializer> boundInitializers, DiagnosticBag diagnostics, out ImportChain firstDebugImports) { firstDebugImports = null; foreach (ImmutableArray <FieldOrPropertyInitializer> siblingInitializers in initializers) { // All sibling initializers share the same parent node and tree so we can reuse the binder // factory across siblings. Unfortunately, we cannot reuse the binder itself, because // individual fields might have their own binders (e.g. because of being declared unsafe). BinderFactory binderFactory = null; foreach (FieldOrPropertyInitializer initializer in siblingInitializers) { FieldSymbol fieldSymbol = initializer.FieldOpt; Debug.Assert((object)fieldSymbol != null); // A constant field of type decimal needs a field initializer, so // check if it is a metadata constant, not just a constant to exclude // decimals. Other constants do not need field initializers. if (!fieldSymbol.IsMetadataConstant) { //Can't assert that this is a regular C# compilation, because we could be in a nested type of a script class. SyntaxReference syntaxRef = initializer.Syntax; #if XSHARP if (syntaxRef.GetSyntax().IsKind(SyntaxKind.VariableDeclarator) || syntaxRef.GetSyntax().IsKind(SyntaxKind.PropertyDeclaration)) { // note that inside SourceMemberContailerSymbol we have added initializers of the wrong type // we handle that here and create the BoundFieldEqualValue wanted by Roslyn var variable = (CSharpSyntaxNode)syntaxRef.GetSyntax(); if (binderFactory == null) { binderFactory = compilation.GetBinderFactory(syntaxRef.SyntaxTree); } Binder pb = binderFactory.GetBinder(variable); Debug.Assert(pb.ContainingMemberOrLambda == fieldSymbol.ContainingType || fieldSymbol.ContainingType.IsImplicitClass); if (firstDebugImports == null) { firstDebugImports = pb.ImportChain; } TypeSymbol type = fieldSymbol.Type; var cv = ConstantValue.Create("", type.SpecialType); var eqvalue = new BoundFieldEqualsValue(variable, fieldSymbol, ImmutableArray <LocalSymbol> .Empty, new BoundLiteral(variable, cv, type) { WasCompilerGenerated = true } ) { WasCompilerGenerated = true }; boundInitializers.Add(eqvalue); continue; } #endif var initializerNode = (EqualsValueClauseSyntax)syntaxRef.GetSyntax(); if (binderFactory == null) { binderFactory = compilation.GetBinderFactory(syntaxRef.SyntaxTree); } Binder parentBinder = binderFactory.GetBinder(initializerNode); Debug.Assert(parentBinder.ContainingMemberOrLambda == fieldSymbol.ContainingType || //should be the binder for the type fieldSymbol.ContainingType.IsImplicitClass); //however, we also allow fields in namespaces to help support script scenarios if (firstDebugImports == null) { firstDebugImports = parentBinder.ImportChain; } parentBinder = new LocalScopeBinder(parentBinder).WithAdditionalFlagsAndContainingMemberOrLambda(BinderFlags.FieldInitializer, fieldSymbol); BoundFieldEqualsValue boundInitializer = BindFieldInitializer(parentBinder, fieldSymbol, initializerNode, diagnostics); boundInitializers.Add(boundInitializer); } } } }
internal static ImmutableArray <LocalSymbol> GetFieldInitializerInfos( CSharpCompilation compilation, FieldInitializers siblingInitializers, ArrayBuilder <FieldInitializerInfo> infos, bool generateDebugInfo, ref ConsList <Imports> firstDebugImports) { // All sibling initializers share the same parent node and tree so we can reuse the binder // factory across siblings. Unfortunately, we cannot reuse the binder itself, because // individual fields might have their own binders (e.g. because of being declared unsafe). BinderFactory binderFactory = null; foreach (FieldInitializer initializer in siblingInitializers.Initializers) { FieldSymbol fieldSymbol = initializer.Field; Debug.Assert((object)fieldSymbol != null); // A constant field of type decimal needs a field initializer, so // check if it is a metadata constant, not just a constant to exclude // decimals. Other constants do not need field initializers. if (!fieldSymbol.IsMetadataConstant) { //Can't assert that this is a regular C# compilation, because we could be in a nested type of a script class. SyntaxReference syntaxRef = initializer.Syntax; var initializerNode = (EqualsValueClauseSyntax)syntaxRef.GetSyntax(); if (binderFactory == null) { binderFactory = compilation.GetBinderFactory(syntaxRef.SyntaxTree); } Binder parentBinder = binderFactory.GetBinder(initializerNode); Debug.Assert(parentBinder.ContainingMemberOrLambda == fieldSymbol.ContainingType || //should be the binder for the type fieldSymbol.ContainingType.IsImplicitClass); //however, we also allow fields in namespaces to help support script scenarios if (generateDebugInfo && firstDebugImports == null) { firstDebugImports = parentBinder.ImportsList; } parentBinder = new LocalScopeBinder(parentBinder).WithAdditionalFlagsAndContainingMemberOrLambda(parentBinder.Flags | BinderFlags.FieldInitializer, fieldSymbol); if (!fieldSymbol.IsConst && !fieldSymbol.IsStatic) { parentBinder = parentBinder.WithPrimaryConstructorParametersIfNecessary(fieldSymbol.ContainingType); } infos.Add(new FieldInitializerInfo(initializer, parentBinder, initializerNode)); } } // See if there are locals that we need to bring into the scope. var locals = default(ImmutableArray <LocalSymbol>); if (siblingInitializers.TypeDeclarationSyntax != null) { locals = GetInitializationScopeLocals(infos); if (!locals.IsDefaultOrEmpty) { for (int i = 0; i < infos.Count; i++) { FieldInitializerInfo info = infos[i]; // Constant initializers is not part of the initialization scope. if (!info.Initializer.Field.IsConst) { infos[i] = new FieldInitializerInfo(info.Initializer, new SimpleLocalScopeBinder(locals, info.Binder), info.EqualsValue); } } } } return(locals); }
/// <summary> /// In regular C#, all field initializers are assignments to fields and the assigned expressions /// may not reference instance members. /// </summary> private static void BindRegularCSharpFieldInitializers( CSharpCompilation compilation, ImmutableArray <FieldInitializers> initializers, ArrayBuilder <BoundInitializer> boundInitializers, DiagnosticBag diagnostics, bool generateDebugInfo, out ConsList <Imports> firstDebugImports) { firstDebugImports = null; foreach (FieldInitializers siblingInitializers in initializers) { // All sibling initializers share the same parent node and tree so we can reuse the binder // factory across siblings. Unfortunately, we cannot reuse the binder itself, because // individual fields might have their own binders (e.g. because of being declared unsafe). BinderFactory binderFactory = null; var infos = ArrayBuilder <FieldInitializerInfo> .GetInstance(); // Exact size is not known up front. foreach (FieldInitializer initializer in siblingInitializers.Initializers) { FieldSymbol fieldSymbol = initializer.Field; Debug.Assert((object)fieldSymbol != null); // A constant field of type decimal needs a field initializer, so // check if it is a metadata constant, not just a constant to exclude // decimals. Other constants do not need field initializers. if (!fieldSymbol.IsMetadataConstant) { //Can't assert that this is a regular C# compilation, because we could be in a nested type of a script class. SyntaxReference syntaxRef = initializer.Syntax; var initializerNode = (EqualsValueClauseSyntax)syntaxRef.GetSyntax(); if (binderFactory == null) { binderFactory = compilation.GetBinderFactory(syntaxRef.SyntaxTree); } Binder parentBinder = binderFactory.GetBinder(initializerNode); Debug.Assert(parentBinder.ContainingMemberOrLambda == fieldSymbol.ContainingType || //should be the binder for the type fieldSymbol.ContainingType.IsImplicitClass); //however, we also allow fields in namespaces to help support script scenarios if (generateDebugInfo && firstDebugImports == null) { firstDebugImports = parentBinder.ImportsList; } parentBinder = new LocalScopeBinder(parentBinder).WithAdditionalFlagsAndContainingMemberOrLambda(parentBinder.Flags | BinderFlags.FieldInitializer, fieldSymbol); if (!fieldSymbol.IsConst && !fieldSymbol.IsStatic) { parentBinder = parentBinder.WithPrimaryConstructorParametersIfNecessary(fieldSymbol.ContainingType); } infos.Add(new FieldInitializerInfo(initializer, parentBinder, initializerNode)); } } // See if there are locals that we need to bring into the scope. var locals = default(ImmutableArray <LocalSymbol>); if (siblingInitializers.TypeDeclarationSyntax != null) { locals = GetInitializationScopeLocals(infos); } ArrayBuilder <BoundInitializer> initializersBuilder = locals.IsDefaultOrEmpty ? boundInitializers : ArrayBuilder <BoundInitializer> .GetInstance(infos.Count); foreach (var info in infos) { Binder binder = info.Binder; ScopedExpressionBinder scopedExpressionBinder = null; // Constant initializers is not part of the initialization scope. if (info.Initializer.Field.IsConst || locals.IsDefault) { binder = scopedExpressionBinder = new ScopedExpressionBinder(binder, info.EqualsValue.Value); } else if (!locals.IsEmpty) { binder = new SimpleLocalScopeBinder(locals, binder); } BoundFieldInitializer boundInitializer = BindFieldInitializer(binder, info.Initializer.Field, info.EqualsValue, diagnostics); if (scopedExpressionBinder != null && !scopedExpressionBinder.Locals.IsDefaultOrEmpty) { boundInitializer = boundInitializer.Update(boundInitializer.Field, scopedExpressionBinder.AddLocalScopeToExpression(boundInitializer.InitialValue)); } initializersBuilder.Add(boundInitializer); } Debug.Assert(locals.IsDefaultOrEmpty == (initializersBuilder == boundInitializers)); if (!locals.IsDefaultOrEmpty) { boundInitializers.Add(new BoundInitializationScope((CSharpSyntaxNode)siblingInitializers.TypeDeclarationSyntax.GetSyntax(), locals, initializersBuilder.ToImmutableAndFree())); } } }