protected override void MethodChecks(DiagnosticBag diagnostics) { var binder = this.DeclaringCompilation. GetBinderFactory(syntaxReferenceOpt.SyntaxTree).GetBinder(ReturnTypeSyntax, GetSyntax(), this); SyntaxToken arglistToken; var signatureBinder = binder.WithAdditionalFlags(BinderFlags.SuppressConstraintChecks); _lazyParameters = ParameterHelpers.MakeParameters( signatureBinder, this, ParameterListSyntax, out arglistToken, diagnostics, allowRefOrOut: true, allowThis: false, beStrict: false); if (arglistToken.Kind() == SyntaxKind.ArgListKeyword) { // This is a parse-time error in the native compiler; it is a semantic analysis error in Roslyn. // error CS1669: __arglist is not valid in this context diagnostics.Add(ErrorCode.ERR_IllegalVarArgs, new SourceLocation(arglistToken)); // Regardless of whether __arglist appears in the source code, we do not mark // the operator method as being a varargs method. } _lazyReturnType = signatureBinder.BindType(ReturnTypeSyntax, diagnostics); if (_lazyReturnType.IsRestrictedType()) { // Method or delegate cannot return type '{0}' diagnostics.Add(ErrorCode.ERR_MethodReturnCantBeRefAny, ReturnTypeSyntax.Location, _lazyReturnType); } if (_lazyReturnType.IsStatic) { // '{0}': static types cannot be used as return types diagnostics.Add(ErrorCode.ERR_ReturnTypeIsStaticClass, ReturnTypeSyntax.Location, _lazyReturnType); } this.SetReturnsVoid(_lazyReturnType.SpecialType == SpecialType.System_Void); // If we have an operator in an interface or static class then we already // have reported that fact as an error. No need to cascade the error further. if (this.ContainingType.IsInterfaceType() || this.ContainingType.IsStatic) { return; } // SPEC: All types referenced in an operator declaration must be at least as accessible // SPEC: as the operator itself. CheckEffectiveAccessibility(_lazyReturnType, _lazyParameters, diagnostics); CheckValueParameters(diagnostics); CheckOperatorSignatures(diagnostics); }
private void TypeChecks(TypeSymbol type, BaseFieldDeclarationSyntax fieldSyntax, VariableDeclaratorSyntax declarator, DiagnosticBag diagnostics) { if (type.IsStatic) { // Cannot declare a variable of static type '{0}' diagnostics.Add(ErrorCode.ERR_VarDeclIsStaticClass, this.Location, type); } else if (type.SpecialType == SpecialType.System_Void) { diagnostics.Add(ErrorCode.ERR_FieldCantHaveVoidType, fieldSyntax.Declaration.Type.Location); } else if (type.IsRestrictedType()) { diagnostics.Add(ErrorCode.ERR_FieldCantBeRefAny, fieldSyntax.Declaration.Type.Location, type); } else if (IsConst && !type.CanBeConst()) { SyntaxToken constToken = default(SyntaxToken); foreach (var modifier in fieldSyntax.Modifiers) { if (modifier.CSharpKind() == SyntaxKind.ConstKeyword) { constToken = modifier; break; } } Debug.Assert(constToken.CSharpKind() == SyntaxKind.ConstKeyword); diagnostics.Add(ErrorCode.ERR_BadConstType, constToken.GetLocation(), type); } else { if (ContainingType.TypeKind == TypeKind.Struct && !IsStatic && !IsConst) { var initializerOpt = declarator.Initializer; if (initializerOpt != null) { // '{0}': cannot have instance field initializers in structs diagnostics.Add(ErrorCode.ERR_FieldInitializerInStruct, this.Location, this); } } if (IsVolatile && !type.IsValidVolatileFieldType()) { // '{0}': a volatile field cannot be of the type '{1}' diagnostics.Add(ErrorCode.ERR_VolatileStruct, this.Location, this, type); } } HashSet <DiagnosticInfo> useSiteDiagnostics = null; if (!this.IsNoMoreVisibleThan(type, ref useSiteDiagnostics)) { // Inconsistent accessibility: field type '{1}' is less accessible than field '{0}' diagnostics.Add(ErrorCode.ERR_BadVisFieldType, this.Location, this, type); } diagnostics.Add(this.Location, useSiteDiagnostics); }
private void TypeChecks(TypeSymbol type, BaseFieldDeclarationSyntax fieldSyntax, VariableDeclaratorSyntax declarator, DiagnosticBag diagnostics) { if (type.IsStatic) { // Cannot declare a variable of static type '{0}' diagnostics.Add(ErrorCode.ERR_VarDeclIsStaticClass, this.Location, type); } else if (type.SpecialType == SpecialType.System_Void) { diagnostics.Add(ErrorCode.ERR_FieldCantHaveVoidType, fieldSyntax.Declaration.Type.Location); } else if (type.IsRestrictedType()) { diagnostics.Add(ErrorCode.ERR_FieldCantBeRefAny, fieldSyntax.Declaration.Type.Location, type); } else if (IsConst && !type.CanBeConst()) { SyntaxToken constToken = default(SyntaxToken); foreach (var modifier in fieldSyntax.Modifiers) { if (modifier.CSharpKind() == SyntaxKind.ConstKeyword) { constToken = modifier; break; } } Debug.Assert(constToken.CSharpKind() == SyntaxKind.ConstKeyword); diagnostics.Add(ErrorCode.ERR_BadConstType, constToken.GetLocation(), type); } else { if (ContainingType.TypeKind == TypeKind.Struct && !IsStatic && !IsConst) { var initializerOpt = declarator.Initializer; if (initializerOpt != null) { // '{0}': cannot have instance field initializers in structs diagnostics.Add(ErrorCode.ERR_FieldInitializerInStruct, this.Location, this); } } if (IsVolatile && !type.IsValidVolatileFieldType()) { // '{0}': a volatile field cannot be of the type '{1}' diagnostics.Add(ErrorCode.ERR_VolatileStruct, this.Location, this, type); } } HashSet<DiagnosticInfo> useSiteDiagnostics = null; if (!this.IsNoMoreVisibleThan(type, ref useSiteDiagnostics)) { // Inconsistent accessibility: field type '{1}' is less accessible than field '{0}' diagnostics.Add(ErrorCode.ERR_BadVisFieldType, this.Location, this, type); } diagnostics.Add(this.Location, useSiteDiagnostics); }
private BoundExpression SetInferredType(TypeSymbol type, Binder binderOpt, DiagnosticBag diagnosticsOpt) { Debug.Assert(binderOpt != null || (object)type != null); Debug.Assert(this.Syntax.Kind() == SyntaxKind.DeclarationExpression); bool inferenceFailed = ((object)type == null); if (inferenceFailed) { type = binderOpt.CreateErrorType("var"); } switch (this.VariableSymbol.Kind) { case SymbolKind.Local: var localSymbol = (SourceLocalSymbol)this.VariableSymbol; if (diagnosticsOpt != null) { if (inferenceFailed) { ReportInferenceFailure(diagnosticsOpt); } else if (localSymbol.ContainingSymbol.Kind == SymbolKind.Method && ((MethodSymbol)localSymbol.ContainingSymbol).IsAsync && type.IsRestrictedType()) { var declaration = (DeclarationExpressionSyntax)this.Syntax; Binder.Error(diagnosticsOpt, ErrorCode.ERR_BadSpecialByRefLocal, declaration.Type, type); } } localSymbol.SetType(type); return new BoundLocal(this.Syntax, localSymbol, constantValueOpt: null, type: type, hasErrors: this.HasErrors || inferenceFailed); case SymbolKind.Field: var fieldSymbol = (GlobalExpressionVariable)this.VariableSymbol; var inferenceDiagnostics = DiagnosticBag.GetInstance(); if (inferenceFailed) { ReportInferenceFailure(inferenceDiagnostics); } fieldSymbol.SetType(type, inferenceDiagnostics); inferenceDiagnostics.Free(); return new BoundFieldAccess(this.Syntax, this.ReceiverOpt, fieldSymbol, null, LookupResultKind.Viable, type, this.HasErrors || inferenceFailed); default: throw ExceptionUtilities.Unreachable; } }
/// <summary> /// Returns the type to be used as a field type; generates errors in case the type is not /// supported for anonymous type fields. /// </summary> private TypeSymbol GetAnonymousTypeFieldType(BoundExpression expression, CSharpSyntaxNode errorSyntax, DiagnosticBag diagnostics, ref bool hasError) { object errorArg = null; TypeSymbol expressionType = expression.Type; if (!expression.HasAnyErrors) { if (expression.HasExpressionType()) { if (expressionType.SpecialType == SpecialType.System_Void) { errorArg = expressionType; expressionType = CreateErrorType(SyntaxFacts.GetText(SyntaxKind.VoidKeyword)); } else if (expressionType.IsUnsafe()) { errorArg = expressionType; // CONSIDER: we could use an explicit error type instead of the unsafe type. } else if (expressionType.IsRestrictedType()) { errorArg = expressionType; } } else { if (expression.Kind == BoundKind.UnboundLambda) { errorArg = ((UnboundLambda)expression).MessageID.Localize(); } else if (expression.Kind == BoundKind.MethodGroup) { errorArg = MessageID.IDS_MethodGroup.Localize(); } else { Debug.Assert(expression.IsLiteralNull(), "How did we successfully bind an expression without a type?"); errorArg = MessageID.IDS_NULL.Localize(); } } } if ((object)expressionType == null) { expressionType = CreateErrorType("error"); } if (errorArg != null) { hasError = true; Error(diagnostics, ErrorCode.ERR_AnonymousTypePropertyAssignedBadValue, errorSyntax, errorArg); // NOTE: ERR_QueryRangeVariableAssignedBadValue is being generated // by query binding code and never reach this point } return(expressionType); }
private BoundExpression SetInferredType(TypeSymbol type, Binder binderOpt, DiagnosticBag diagnosticsOpt) { Debug.Assert(binderOpt != null || (object)type != null); Debug.Assert(this.Syntax.Kind() == SyntaxKind.DeclarationExpression); bool inferenceFailed = ((object)type == null); if (inferenceFailed) { type = binderOpt.CreateErrorType("var"); } switch (this.VariableSymbol.Kind) { case SymbolKind.Local: var localSymbol = (SourceLocalSymbol)this.VariableSymbol; if (diagnosticsOpt != null) { if (inferenceFailed) { ReportInferenceFailure(diagnosticsOpt); } else if (localSymbol.ContainingSymbol.Kind == SymbolKind.Method && ((MethodSymbol)localSymbol.ContainingSymbol).IsAsync && type.IsRestrictedType()) { var declaration = (TypedVariableComponentSyntax)((DeclarationExpressionSyntax)this.Syntax).VariableComponent; Binder.Error(diagnosticsOpt, ErrorCode.ERR_BadSpecialByRefLocal, declaration.Type, type); } } localSymbol.SetType(type); return(new BoundLocal(this.Syntax, localSymbol, constantValueOpt: null, type: type, hasErrors: this.HasErrors || inferenceFailed)); case SymbolKind.Field: var fieldSymbol = (SourceMemberFieldSymbolFromDesignation)this.VariableSymbol; var inferenceDiagnostics = DiagnosticBag.GetInstance(); if (inferenceFailed) { ReportInferenceFailure(inferenceDiagnostics); } fieldSymbol.SetType(type, inferenceDiagnostics); inferenceDiagnostics.Free(); return(new BoundFieldAccess(this.Syntax, this.ReceiverOpt, fieldSymbol, null, LookupResultKind.Viable, type, this.HasErrors || inferenceFailed)); default: throw ExceptionUtilities.Unreachable; } }
protected void TypeChecks(TypeSymbol type, BindingDiagnosticBag diagnostics) { if (type.HasFileLocalTypes() && !ContainingType.HasFileLocalTypes()) { diagnostics.Add(ErrorCode.ERR_FileTypeDisallowedInSignature, this.ErrorLocation, type, ContainingType); } else if (type.IsStatic) { // Cannot declare a variable of static type '{0}' diagnostics.Add(ErrorCode.ERR_VarDeclIsStaticClass, this.ErrorLocation, type); } else if (type.IsVoidType()) { diagnostics.Add(ErrorCode.ERR_FieldCantHaveVoidType, TypeSyntax?.Location ?? this.Locations[0]); } else if (type.IsRestrictedType(ignoreSpanLikeTypes: true)) { diagnostics.Add(ErrorCode.ERR_FieldCantBeRefAny, TypeSyntax?.Location ?? this.Locations[0], type); } else if (type.IsRefLikeType && (this.IsStatic || !containingType.IsRefLikeType)) { diagnostics.Add(ErrorCode.ERR_FieldAutoPropCantBeByRefLike, TypeSyntax?.Location ?? this.Locations[0], type); } else if (IsConst && !type.CanBeConst()) { SyntaxToken constToken = default(SyntaxToken); foreach (var modifier in ModifiersTokenList) { if (modifier.Kind() == SyntaxKind.ConstKeyword) { constToken = modifier; break; } } Debug.Assert(constToken.Kind() == SyntaxKind.ConstKeyword); diagnostics.Add(ErrorCode.ERR_BadConstType, constToken.GetLocation(), type); } else if (IsVolatile && !type.IsValidVolatileFieldType()) { // '{0}': a volatile field cannot be of the type '{1}' diagnostics.Add(ErrorCode.ERR_VolatileStruct, this.ErrorLocation, this, type); } CompoundUseSiteInfo <AssemblySymbol> useSiteInfo = new CompoundUseSiteInfo <AssemblySymbol>(diagnostics, ContainingAssembly); if (!this.IsNoMoreVisibleThan(type, ref useSiteInfo)) { // Inconsistent accessibility: field type '{1}' is less accessible than field '{0}' diagnostics.Add(ErrorCode.ERR_BadVisFieldType, this.ErrorLocation, this, type); } diagnostics.Add(this.ErrorLocation, useSiteInfo); }
protected override TypeSymbol MakeReturnType(Binder bodyBinder, DelegateDeclarationSyntax syntax, DiagnosticBag diagnostics) { TypeSymbol returnType = bodyBinder.BindType(syntax.ReturnType, diagnostics); if (returnType.IsRestrictedType()) { // Method or delegate cannot return type '{0}' diagnostics.Add(ErrorCode.ERR_MethodReturnCantBeRefAny, syntax.ReturnType.Location, returnType); } return(returnType); }
protected void TypeChecks(TypeSymbol type, DiagnosticBag diagnostics) { if (type.IsStatic) { // Cannot declare a variable of static type '{0}' diagnostics.Add(ErrorCode.ERR_VarDeclIsStaticClass, this.ErrorLocation, type); } else if (type.SpecialType == SpecialType.System_Void) { diagnostics.Add(ErrorCode.ERR_FieldCantHaveVoidType, TypeSyntax.Location); } else if (type.IsRestrictedType(ignoreSpanLikeTypes: true)) { diagnostics.Add(ErrorCode.ERR_FieldCantBeRefAny, TypeSyntax.Location, type); } else if (type.IsByRefLikeType && (this.IsStatic || !containingType.IsByRefLikeType)) { diagnostics.Add(ErrorCode.ERR_FieldAutoPropCantBeByRefLike, TypeSyntax.Location, type); } else if (IsConst && !type.CanBeConst()) { SyntaxToken constToken = default(SyntaxToken); foreach (var modifier in ModifiersTokenList) { if (modifier.Kind() == SyntaxKind.ConstKeyword) { constToken = modifier; break; } } Debug.Assert(constToken.Kind() == SyntaxKind.ConstKeyword); diagnostics.Add(ErrorCode.ERR_BadConstType, constToken.GetLocation(), type); } else if (IsVolatile && !type.IsValidVolatileFieldType()) { // '{0}': a volatile field cannot be of the type '{1}' diagnostics.Add(ErrorCode.ERR_VolatileStruct, this.ErrorLocation, this, type); } HashSet <DiagnosticInfo> useSiteDiagnostics = null; if (!this.IsNoMoreVisibleThan(type, ref useSiteDiagnostics)) { // Inconsistent accessibility: field type '{1}' is less accessible than field '{0}' diagnostics.Add(ErrorCode.ERR_BadVisFieldType, this.ErrorLocation, this, type); } diagnostics.Add(this.ErrorLocation, useSiteDiagnostics); }
protected void TypeChecks(TypeSymbol type, DiagnosticBag diagnostics) { if (type.IsStatic) { // Cannot declare a variable of static type '{0}' diagnostics.Add(ErrorCode.ERR_VarDeclIsStaticClass, this.ErrorLocation, type); } else if (type.SpecialType == SpecialType.System_Void) { diagnostics.Add(ErrorCode.ERR_FieldCantHaveVoidType, TypeSyntax.Location); } else if (type.IsRestrictedType()) { diagnostics.Add(ErrorCode.ERR_FieldCantBeRefAny, TypeSyntax.Location, type); } else if (IsConst && !type.CanBeConst()) { SyntaxToken constToken = default(SyntaxToken); foreach (var modifier in ModifiersTokenList) { if (modifier.Kind() == SyntaxKind.ConstKeyword) { constToken = modifier; break; } } Debug.Assert(constToken.Kind() == SyntaxKind.ConstKeyword); diagnostics.Add(ErrorCode.ERR_BadConstType, constToken.GetLocation(), type); } else if (IsVolatile && !type.IsValidVolatileFieldType()) { // '{0}': a volatile field cannot be of the type '{1}' diagnostics.Add(ErrorCode.ERR_VolatileStruct, this.ErrorLocation, this, type); } HashSet<DiagnosticInfo> useSiteDiagnostics = null; if (!this.IsNoMoreVisibleThan(type, ref useSiteDiagnostics)) { // Inconsistent accessibility: field type '{1}' is less accessible than field '{0}' diagnostics.Add(ErrorCode.ERR_BadVisFieldType, this.ErrorLocation, this, type); } diagnostics.Add(this.ErrorLocation, useSiteDiagnostics); }
/// <summary> /// Returns the type to be used as a field type; generates errors in case the type is not /// supported for anonymous type fields. /// </summary> private TypeSymbol GetAnonymousTypeFieldType(BoundExpression expression, CSharpSyntaxNode errorSyntax, DiagnosticBag diagnostics, ref bool hasError) { object errorArg = null; TypeSymbol expressionType = expression.Type; if (!expression.HasAnyErrors) { if (expression.HasExpressionType()) { if (expressionType.SpecialType == SpecialType.System_Void) { errorArg = expressionType; expressionType = CreateErrorType(SyntaxFacts.GetText(SyntaxKind.VoidKeyword)); } else if (expressionType.IsUnsafe()) { errorArg = expressionType; // CONSIDER: we could use an explicit error type instead of the unsafe type. } else if (expressionType.IsRestrictedType()) { errorArg = expressionType; } } else { errorArg = expression.Display; } } if ((object)expressionType == null) { expressionType = CreateErrorType("error"); } if (errorArg != null) { hasError = true; Error(diagnostics, ErrorCode.ERR_AnonymousTypePropertyAssignedBadValue, errorSyntax, errorArg); // NOTE: ERR_QueryRangeVariableAssignedBadValue is being generated // by query binding code and never reach this point } return(expressionType); }
protected BoundLocalDeclaration BindVariableDeclaration( SourceLocalSymbol localSymbol, LocalDeclarationKind kind, bool isVar, VariableDeclaratorSyntax declarator, TypeSyntax typeSyntax, TypeSymbol declTypeOpt, AliasSymbol aliasOpt, DiagnosticBag diagnostics, CSharpSyntaxNode associatedSyntaxNode = null) { Debug.Assert(declarator != null); Debug.Assert((object)declTypeOpt != null || isVar); Debug.Assert(typeSyntax != null); var localDiagnostics = DiagnosticBag.GetInstance(); // if we are not given desired syntax, we use declarator associatedSyntaxNode = associatedSyntaxNode ?? declarator; bool hasErrors = false; BoundExpression initializerOpt; // Check for variable declaration errors. hasErrors |= this.ValidateDeclarationNameConflictsInScope(localSymbol, localDiagnostics); EqualsValueClauseSyntax equalsValueClauseSyntax = declarator.Initializer; if (isVar) { aliasOpt = null; var binder = new ImplicitlyTypedLocalBinder(this, localSymbol); initializerOpt = binder.BindInferredVariableInitializer(localDiagnostics, equalsValueClauseSyntax, declarator); // If we got a good result then swap the inferred type for the "var" if ((object)initializerOpt?.Type != null) { declTypeOpt = initializerOpt.Type; if (declTypeOpt.SpecialType == SpecialType.System_Void) { Error(localDiagnostics, ErrorCode.ERR_ImplicitlyTypedVariableAssignedBadValue, declarator, declTypeOpt); declTypeOpt = CreateErrorType("var"); hasErrors = true; } if (!declTypeOpt.IsErrorType()) { if (declTypeOpt.IsStatic) { Error(localDiagnostics, ErrorCode.ERR_VarDeclIsStaticClass, typeSyntax, initializerOpt.Type); hasErrors = true; } } } else { declTypeOpt = CreateErrorType("var"); hasErrors = true; } } else { if (ReferenceEquals(equalsValueClauseSyntax, null)) { initializerOpt = null; } else { // Basically inlined BindVariableInitializer, but with conversion optional. initializerOpt = BindPossibleArrayInitializer(equalsValueClauseSyntax.Value, declTypeOpt, localDiagnostics); if (kind != LocalDeclarationKind.FixedVariable) { // If this is for a fixed statement, we'll do our own conversion since there are some special cases. initializerOpt = GenerateConversionForAssignment(declTypeOpt, initializerOpt, localDiagnostics); } } } Debug.Assert((object)declTypeOpt != null); if (kind == LocalDeclarationKind.FixedVariable) { // NOTE: this is an error, but it won't prevent further binding. if (isVar) { if (!hasErrors) { Error(localDiagnostics, ErrorCode.ERR_ImplicitlyTypedLocalCannotBeFixed, declarator); hasErrors = true; } } if (!declTypeOpt.IsPointerType()) { if (!hasErrors) { Error(localDiagnostics, ErrorCode.ERR_BadFixedInitType, declarator); hasErrors = true; } } else if (!IsValidFixedVariableInitializer(declTypeOpt, localSymbol, ref initializerOpt, localDiagnostics)) { hasErrors = true; } } if (this.ContainingMemberOrLambda.Kind == SymbolKind.Method && ((MethodSymbol)this.ContainingMemberOrLambda).IsAsync && declTypeOpt.IsRestrictedType()) { Error(localDiagnostics, ErrorCode.ERR_BadSpecialByRefLocal, typeSyntax, declTypeOpt); hasErrors = true; } DeclareLocalVariable( localSymbol, declarator.Identifier, declTypeOpt); Debug.Assert((object)localSymbol != null); ImmutableArray<BoundExpression> arguments = BindDeclaratorArguments(declarator, localDiagnostics); if (kind == LocalDeclarationKind.FixedVariable || kind == LocalDeclarationKind.UsingVariable) { // CONSIDER: The error message is "you must provide an initializer in a fixed // CONSIDER: or using declaration". The error message could be targetted to // CONSIDER: the actual situation. "you must provide an initializer in a // CONSIDER: 'fixed' declaration." if (initializerOpt == null) { Error(localDiagnostics, ErrorCode.ERR_FixedMustInit, declarator); hasErrors = true; } } else if (kind == LocalDeclarationKind.Constant && initializerOpt != null && !localDiagnostics.HasAnyResolvedErrors()) { var constantValueDiagnostics = localSymbol.GetConstantValueDiagnostics(initializerOpt); foreach (var diagnostic in constantValueDiagnostics) { diagnostics.Add(diagnostic); hasErrors = true; } } diagnostics.AddRangeAndFree(localDiagnostics); var boundDeclType = new BoundTypeExpression(typeSyntax, aliasOpt, inferredType: isVar, type: declTypeOpt); return new BoundLocalDeclaration(associatedSyntaxNode, localSymbol, boundDeclType, initializerOpt, arguments, hasErrors); }
// See TypeBind::CheckSingleConstraint. private static bool CheckConstraints( Symbol containingSymbol, ConversionsBase conversions, TypeMap substitution, TypeParameterSymbol typeParameter, TypeSymbol typeArgument, Compilation currentCompilation, ArrayBuilder<TypeParameterDiagnosticInfo> diagnosticsBuilder, ref ArrayBuilder<TypeParameterDiagnosticInfo> useSiteDiagnosticsBuilder, HashSet<TypeParameterSymbol> ignoreTypeConstraintsDependentOnTypeParametersOpt) { Debug.Assert(substitution != null); // The type parameters must be original definitions of type parameters from the containing symbol. Debug.Assert(ReferenceEquals(typeParameter.ContainingSymbol, containingSymbol.OriginalDefinition)); if (typeArgument.IsErrorType()) { return true; } if (typeArgument.IsPointerType() || typeArgument.IsRestrictedType() || typeArgument.SpecialType == SpecialType.System_Void) { // "The type '{0}' may not be used as a type argument" diagnosticsBuilder.Add(new TypeParameterDiagnosticInfo(typeParameter, new CSDiagnosticInfo(ErrorCode.ERR_BadTypeArgument, typeArgument))); return false; } if (typeArgument.IsStatic) { // "'{0}': static types cannot be used as type arguments" diagnosticsBuilder.Add(new TypeParameterDiagnosticInfo(typeParameter, new CSDiagnosticInfo(ErrorCode.ERR_GenericArgIsStaticClass, typeArgument))); return false; } if (typeParameter.HasReferenceTypeConstraint && !typeArgument.IsReferenceType) { // "The type '{2}' must be a reference type in order to use it as parameter '{1}' in the generic type or method '{0}'" diagnosticsBuilder.Add(new TypeParameterDiagnosticInfo(typeParameter, new CSDiagnosticInfo(ErrorCode.ERR_RefConstraintNotSatisfied, containingSymbol.ConstructedFrom(), typeParameter, typeArgument))); return false; } if (typeParameter.HasValueTypeConstraint && !typeArgument.IsNonNullableValueType()) { // "The type '{2}' must be a non-nullable value type in order to use it as parameter '{1}' in the generic type or method '{0}'" diagnosticsBuilder.Add(new TypeParameterDiagnosticInfo(typeParameter, new CSDiagnosticInfo(ErrorCode.ERR_ValConstraintNotSatisfied, containingSymbol.ConstructedFrom(), typeParameter, typeArgument))); return false; } // The type parameters for a constructed type/method are the type parameters of // the ConstructedFrom type/method, so the constraint types are not substituted. // For instance with "class C<T, U> where T : U", the type parameter for T in "C<object, int>" // has constraint "U", not "int". We need to substitute the constraints from the // original definition of the type parameters using the map from the constructed symbol. var constraintTypes = ArrayBuilder<TypeSymbol>.GetInstance(); HashSet<DiagnosticInfo> useSiteDiagnostics = null; substitution.SubstituteTypesDistinctWithoutModifiers(typeParameter.ConstraintTypesWithDefinitionUseSiteDiagnostics(ref useSiteDiagnostics), constraintTypes, ignoreTypeConstraintsDependentOnTypeParametersOpt); bool hasError = false; foreach (var constraintType in constraintTypes) { if (SatisfiesConstraintType(conversions, typeArgument, constraintType, ref useSiteDiagnostics)) { continue; } ErrorCode errorCode; if (typeArgument.IsReferenceType) { errorCode = ErrorCode.ERR_GenericConstraintNotSatisfiedRefType; } else if (typeArgument.IsNullableType()) { errorCode = constraintType.IsInterfaceType() ? ErrorCode.ERR_GenericConstraintNotSatisfiedNullableInterface : ErrorCode.ERR_GenericConstraintNotSatisfiedNullableEnum; } else if (typeArgument.TypeKind == TypeKind.TypeParameter) { errorCode = ErrorCode.ERR_GenericConstraintNotSatisfiedTyVar; } else { errorCode = ErrorCode.ERR_GenericConstraintNotSatisfiedValType; } SymbolDistinguisher distinguisher = new SymbolDistinguisher(currentCompilation, constraintType, typeArgument); diagnosticsBuilder.Add(new TypeParameterDiagnosticInfo(typeParameter, new CSDiagnosticInfo(errorCode, containingSymbol.ConstructedFrom(), distinguisher.First, typeParameter, distinguisher.Second))); hasError = true; } if (AppendUseSiteDiagnostics(useSiteDiagnostics, typeParameter, ref useSiteDiagnosticsBuilder)) { hasError = true; } constraintTypes.Free(); // Check the constructor constraint. if (typeParameter.HasConstructorConstraint && !SatisfiesConstructorConstraint(typeArgument)) { // "'{2}' must be a non-abstract type with a public parameterless constructor in order to use it as parameter '{1}' in the generic type or method '{0}'" diagnosticsBuilder.Add(new TypeParameterDiagnosticInfo(typeParameter, new CSDiagnosticInfo(ErrorCode.ERR_NewConstraintNotSatisfied, containingSymbol.ConstructedFrom(), typeParameter, typeArgument))); return false; } return !hasError; }
private void MethodChecks(MethodDeclarationSyntax syntax, Binder withTypeParamsBinder, DiagnosticBag diagnostics) { SyntaxToken arglistToken; // Constraint checking for parameter and return types must be delayed until // the method has been added to the containing type member list since // evaluating the constraints may depend on accessing this method from // the container (comparing this method to others to find overrides for // instance). Constraints are checked in AfterAddingTypeMembersChecks. var signatureBinder = withTypeParamsBinder.WithAdditionalFlagsAndContainingMemberOrLambda(BinderFlags.SuppressConstraintChecks, this); _lazyParameters = ParameterHelpers.MakeParameters(signatureBinder, this, syntax.ParameterList, true, out arglistToken, diagnostics, false); _lazyIsVararg = (arglistToken.Kind() == SyntaxKind.ArgListKeyword); RefKind refKind; var returnTypeSyntax = syntax.ReturnType.SkipRef(out refKind); _lazyReturnType = signatureBinder.BindType(returnTypeSyntax, diagnostics); if (_lazyReturnType.IsRestrictedType()) { if (_lazyReturnType.SpecialType == SpecialType.System_TypedReference && (this.ContainingType.SpecialType == SpecialType.System_TypedReference || this.ContainingType.SpecialType == SpecialType.System_ArgIterator)) { // Two special cases: methods in the special types TypedReference and ArgIterator are allowed to return TypedReference } else { // Method or delegate cannot return type '{0}' diagnostics.Add(ErrorCode.ERR_MethodReturnCantBeRefAny, syntax.ReturnType.Location, _lazyReturnType); } } var returnsVoid = _lazyReturnType.SpecialType == SpecialType.System_Void; if (this.RefKind != RefKind.None && returnsVoid) { Debug.Assert(returnTypeSyntax.HasErrors); } // set ReturnsVoid flag this.SetReturnsVoid(returnsVoid); var location = this.Locations[0]; this.CheckEffectiveAccessibility(_lazyReturnType, _lazyParameters, diagnostics); // Checks taken from MemberDefiner::defineMethod if (this.Name == WellKnownMemberNames.DestructorName && this.ParameterCount == 0 && this.Arity == 0 && this.ReturnsVoid) { diagnostics.Add(ErrorCode.WRN_FinalizeMethod, location); } // errors relevant for extension methods if (IsExtensionMethod) { var parameter0Type = this.Parameters[0].Type; if (!parameter0Type.IsValidExtensionParameterType()) { // Duplicate Dev10 behavior by selecting the parameter type. var parameterSyntax = syntax.ParameterList.Parameters[0]; Debug.Assert(parameterSyntax.Type != null); var loc = parameterSyntax.Type.Location; diagnostics.Add(ErrorCode.ERR_BadTypeforThis, loc, parameter0Type); } else if ((object)ContainingType.ContainingType != null) { diagnostics.Add(ErrorCode.ERR_ExtensionMethodsDecl, location, ContainingType.Name); } else if (!ContainingType.IsScriptClass && !(ContainingType.IsStatic && ContainingType.Arity == 0)) { // Duplicate Dev10 behavior by selecting the containing type identifier. However if there // is no containing type (in the interactive case for instance), select the method identifier. var typeDecl = syntax.Parent as TypeDeclarationSyntax; var identifier = (typeDecl != null) ? typeDecl.Identifier : syntax.Identifier; var loc = identifier.GetLocation(); diagnostics.Add(ErrorCode.ERR_BadExtensionAgg, loc); } else if (!IsStatic) { diagnostics.Add(ErrorCode.ERR_BadExtensionMeth, location); } else { // Verify ExtensionAttribute is available. var attributeConstructor = withTypeParamsBinder.Compilation.GetWellKnownTypeMember(WellKnownMember.System_Runtime_CompilerServices_ExtensionAttribute__ctor); if ((object)attributeConstructor == null) { var memberDescriptor = WellKnownMembers.GetDescriptor(WellKnownMember.System_Runtime_CompilerServices_ExtensionAttribute__ctor); // do not use Binder.ReportUseSiteErrorForAttributeCtor in this case, because we'll need to report a special error id, not a generic use site error. diagnostics.Add( ErrorCode.ERR_ExtensionAttrNotFound, syntax.ParameterList.Parameters[0].Modifiers.FirstOrDefault(SyntaxKind.ThisKeyword).GetLocation(), memberDescriptor.DeclaringTypeMetadataName); } } } if (this.MethodKind == MethodKind.UserDefinedOperator) { foreach (var p in this.Parameters) { if (p.RefKind != RefKind.None) { diagnostics.Add(ErrorCode.ERR_IllegalRefParam, location); break; } } } else if (IsPartial) { // check that there are no out parameters in a partial foreach (var p in this.Parameters) { if (p.RefKind == RefKind.Out) { diagnostics.Add(ErrorCode.ERR_PartialMethodCannotHaveOutParameters, location); break; } } if (MethodKind == MethodKind.ExplicitInterfaceImplementation) { diagnostics.Add(ErrorCode.ERR_PartialMethodNotExplicit, location); } if (!ContainingType.IsPartial() || ContainingType.IsInterface) { diagnostics.Add(ErrorCode.ERR_PartialMethodOnlyInPartialClass, location); } } if (!IsPartial) { LazyAsyncMethodChecks(CancellationToken.None); Debug.Assert(state.HasComplete(CompletionPart.FinishAsyncMethodChecks)); } // The runtime will not treat this method as an override or implementation of another // method unless both the signatures and the custom modifiers match. Hence, in the // case of overrides and *explicit* implementations, we need to copy the custom modifiers // that are in the signature of the overridden/implemented method. (From source, we know // that there can only be one such method, so there are no conflicts.) This is // unnecessary for implicit implementations because, if the custom modifiers don't match, // we'll insert a bridge method (an explicit implementation that delegates to the implicit // implementation) with the correct custom modifiers // (see SourceNamedTypeSymbol.ImplementInterfaceMember). // Note: we're checking if the syntax indicates explicit implementation rather, // than if explicitInterfaceType is null because we don't want to look for an // overridden property if this is supposed to be an explicit implementation. if (syntax.ExplicitInterfaceSpecifier == null) { Debug.Assert(_lazyExplicitInterfaceImplementations.IsDefault); _lazyExplicitInterfaceImplementations = ImmutableArray <MethodSymbol> .Empty; // This value may not be correct, but we need something while we compute this.OverriddenMethod. // May be re-assigned below. Debug.Assert(_lazyReturnTypeCustomModifiers.IsDefault); Debug.Assert(_lazyCountOfCustomModifiersPrecedingByRef == 0); _lazyReturnTypeCustomModifiers = ImmutableArray <CustomModifier> .Empty; _lazyCountOfCustomModifiersPrecedingByRef = 0; // If this method is an override, we may need to copy custom modifiers from // the overridden method (so that the runtime will recognize it as an override). // We check for this case here, while we can still modify the parameters and // return type without losing the appearance of immutability. if (this.IsOverride) { // This computation will necessarily be performed with partially incomplete // information. There is no way we can determine the complete signature // (i.e. including custom modifiers) until we have found the method that // this method overrides. To accommodate this, MethodSymbol.OverriddenOrHiddenMembers // is written to allow relaxed matching of custom modifiers for source methods, // on the assumption that they will be updated appropriately. MethodSymbol overriddenMethod = this.OverriddenMethod; if ((object)overriddenMethod != null) { CustomModifierUtils.CopyMethodCustomModifiers(overriddenMethod, this, out _lazyReturnType, out _lazyReturnTypeCustomModifiers, out _lazyCountOfCustomModifiersPrecedingByRef, out _lazyParameters, alsoCopyParamsModifier: true); } } } else if ((object)_explicitInterfaceType != null) { //do this last so that it can assume the method symbol is constructed (except for ExplicitInterfaceImplementation) MethodSymbol implementedMethod = this.FindExplicitlyImplementedMethod(_explicitInterfaceType, syntax.Identifier.ValueText, syntax.ExplicitInterfaceSpecifier, diagnostics); if ((object)implementedMethod != null) { Debug.Assert(_lazyExplicitInterfaceImplementations.IsDefault); _lazyExplicitInterfaceImplementations = ImmutableArray.Create <MethodSymbol>(implementedMethod); CustomModifierUtils.CopyMethodCustomModifiers(implementedMethod, this, out _lazyReturnType, out _lazyReturnTypeCustomModifiers, out _lazyCountOfCustomModifiersPrecedingByRef, out _lazyParameters, alsoCopyParamsModifier: false); } else { Debug.Assert(_lazyExplicitInterfaceImplementations.IsDefault); _lazyExplicitInterfaceImplementations = ImmutableArray <MethodSymbol> .Empty; Debug.Assert(_lazyReturnTypeCustomModifiers.IsDefault); Debug.Assert(_lazyCountOfCustomModifiersPrecedingByRef == 0); _lazyReturnTypeCustomModifiers = ImmutableArray <CustomModifier> .Empty; _lazyCountOfCustomModifiersPrecedingByRef = 0; } } CheckModifiers(location, diagnostics); }
private void MethodChecks(MethodDeclarationSyntax syntax, Binder withTypeParamsBinder, DiagnosticBag diagnostics) { SyntaxToken arglistToken; // Constraint checking for parameter and return types must be delayed until // the method has been added to the containing type member list since // evaluating the constraints may depend on accessing this method from // the container (comparing this method to others to find overrides for // instance). Constraints are checked in AfterAddingTypeMembersChecks. var signatureBinder = withTypeParamsBinder.WithAdditionalFlagsAndContainingMemberOrLambda(BinderFlags.SuppressConstraintChecks, this); _lazyParameters = ParameterHelpers.MakeParameters(signatureBinder, this, syntax.ParameterList, true, out arglistToken, diagnostics, false); _lazyIsVararg = (arglistToken.Kind() == SyntaxKind.ArgListKeyword); RefKind refKind; var returnTypeSyntax = syntax.ReturnType.SkipRef(out refKind); _lazyReturnType = signatureBinder.BindType(returnTypeSyntax, diagnostics); if (_lazyReturnType.IsRestrictedType()) { if (_lazyReturnType.SpecialType == SpecialType.System_TypedReference && (this.ContainingType.SpecialType == SpecialType.System_TypedReference || this.ContainingType.SpecialType == SpecialType.System_ArgIterator)) { // Two special cases: methods in the special types TypedReference and ArgIterator are allowed to return TypedReference } else { // Method or delegate cannot return type '{0}' diagnostics.Add(ErrorCode.ERR_MethodReturnCantBeRefAny, syntax.ReturnType.Location, _lazyReturnType); } } var returnsVoid = _lazyReturnType.SpecialType == SpecialType.System_Void; if (this.RefKind != RefKind.None && returnsVoid) { Debug.Assert(returnTypeSyntax.HasErrors); } // set ReturnsVoid flag this.SetReturnsVoid(returnsVoid); var location = this.Locations[0]; this.CheckEffectiveAccessibility(_lazyReturnType, _lazyParameters, diagnostics); // Checks taken from MemberDefiner::defineMethod if (this.Name == WellKnownMemberNames.DestructorName && this.ParameterCount == 0 && this.Arity == 0 && this.ReturnsVoid) { diagnostics.Add(ErrorCode.WRN_FinalizeMethod, location); } // errors relevant for extension methods if (IsExtensionMethod) { var parameter0Type = this.Parameters[0].Type; if (!parameter0Type.IsValidExtensionParameterType()) { // Duplicate Dev10 behavior by selecting the parameter type. var parameterSyntax = syntax.ParameterList.Parameters[0]; Debug.Assert(parameterSyntax.Type != null); var loc = parameterSyntax.Type.Location; diagnostics.Add(ErrorCode.ERR_BadTypeforThis, loc, parameter0Type); } else if ((object)ContainingType.ContainingType != null) { diagnostics.Add(ErrorCode.ERR_ExtensionMethodsDecl, location, ContainingType.Name); } else if (!ContainingType.IsScriptClass && !(ContainingType.IsStatic && ContainingType.Arity == 0)) { // Duplicate Dev10 behavior by selecting the containing type identifier. However if there // is no containing type (in the interactive case for instance), select the method identifier. var typeDecl = syntax.Parent as TypeDeclarationSyntax; var identifier = (typeDecl != null) ? typeDecl.Identifier : syntax.Identifier; var loc = identifier.GetLocation(); diagnostics.Add(ErrorCode.ERR_BadExtensionAgg, loc); } else if (!IsStatic) { diagnostics.Add(ErrorCode.ERR_BadExtensionMeth, location); } else { // Verify ExtensionAttribute is available. var attributeConstructor = withTypeParamsBinder.Compilation.GetWellKnownTypeMember(WellKnownMember.System_Runtime_CompilerServices_ExtensionAttribute__ctor); if ((object)attributeConstructor == null) { var memberDescriptor = WellKnownMembers.GetDescriptor(WellKnownMember.System_Runtime_CompilerServices_ExtensionAttribute__ctor); // do not use Binder.ReportUseSiteErrorForAttributeCtor in this case, because we'll need to report a special error id, not a generic use site error. diagnostics.Add( ErrorCode.ERR_ExtensionAttrNotFound, syntax.ParameterList.Parameters[0].Modifiers.FirstOrDefault(SyntaxKind.ThisKeyword).GetLocation(), memberDescriptor.DeclaringTypeMetadataName); } } } if (this.MethodKind == MethodKind.UserDefinedOperator) { foreach (var p in this.Parameters) { if (p.RefKind != RefKind.None) { diagnostics.Add(ErrorCode.ERR_IllegalRefParam, location); break; } } } else if (IsPartial) { // check that there are no out parameters in a partial foreach (var p in this.Parameters) { if (p.RefKind == RefKind.Out) { diagnostics.Add(ErrorCode.ERR_PartialMethodCannotHaveOutParameters, location); break; } } if (MethodKind == MethodKind.ExplicitInterfaceImplementation) { diagnostics.Add(ErrorCode.ERR_PartialMethodNotExplicit, location); } if (!ContainingType.IsPartial() || ContainingType.IsInterface) { diagnostics.Add(ErrorCode.ERR_PartialMethodOnlyInPartialClass, location); } } if (!IsPartial) { LazyAsyncMethodChecks(CancellationToken.None); Debug.Assert(state.HasComplete(CompletionPart.FinishAsyncMethodChecks)); } // The runtime will not treat this method as an override or implementation of another // method unless both the signatures and the custom modifiers match. Hence, in the // case of overrides and *explicit* implementations, we need to copy the custom modifiers // that are in the signature of the overridden/implemented method. (From source, we know // that there can only be one such method, so there are no conflicts.) This is // unnecessary for implicit implementations because, if the custom modifiers don't match, // we'll insert a bridge method (an explicit implementation that delegates to the implicit // implementation) with the correct custom modifiers // (see SourceNamedTypeSymbol.ImplementInterfaceMember). // Note: we're checking if the syntax indicates explicit implementation rather, // than if explicitInterfaceType is null because we don't want to look for an // overridden property if this is supposed to be an explicit implementation. if (syntax.ExplicitInterfaceSpecifier == null) { Debug.Assert(_lazyExplicitInterfaceImplementations.IsDefault); _lazyExplicitInterfaceImplementations = ImmutableArray<MethodSymbol>.Empty; // This value may not be correct, but we need something while we compute this.OverriddenMethod. // May be re-assigned below. Debug.Assert(_lazyReturnTypeCustomModifiers.IsDefault); _lazyReturnTypeCustomModifiers = ImmutableArray<CustomModifier>.Empty; // If this method is an override, we may need to copy custom modifiers from // the overridden method (so that the runtime will recognize it as an override). // We check for this case here, while we can still modify the parameters and // return type without losing the appearance of immutability. if (this.IsOverride) { // This computation will necessarily be performed with partially incomplete // information. There is no way we can determine the complete signature // (i.e. including custom modifiers) until we have found the method that // this method overrides. To accommodate this, MethodSymbol.OverriddenOrHiddenMembers // is written to allow relaxed matching of custom modifiers for source methods, // on the assumption that they will be updated appropriately. MethodSymbol overriddenMethod = this.OverriddenMethod; if ((object)overriddenMethod != null) { CustomModifierUtils.CopyMethodCustomModifiers(overriddenMethod, this, out _lazyReturnType, out _lazyReturnTypeCustomModifiers, out _lazyParameters, alsoCopyParamsModifier: true); } } } else if ((object)_explicitInterfaceType != null) { //do this last so that it can assume the method symbol is constructed (except for ExplicitInterfaceImplementation) MethodSymbol implementedMethod = this.FindExplicitlyImplementedMethod(_explicitInterfaceType, syntax.Identifier.ValueText, syntax.ExplicitInterfaceSpecifier, diagnostics); if ((object)implementedMethod != null) { Debug.Assert(_lazyExplicitInterfaceImplementations.IsDefault); _lazyExplicitInterfaceImplementations = ImmutableArray.Create<MethodSymbol>(implementedMethod); CustomModifierUtils.CopyMethodCustomModifiers(implementedMethod, this, out _lazyReturnType, out _lazyReturnTypeCustomModifiers, out _lazyParameters, alsoCopyParamsModifier: false); } else { Debug.Assert(_lazyExplicitInterfaceImplementations.IsDefault); _lazyExplicitInterfaceImplementations = ImmutableArray<MethodSymbol>.Empty; Debug.Assert(_lazyReturnTypeCustomModifiers.IsDefault); _lazyReturnTypeCustomModifiers = ImmutableArray<CustomModifier>.Empty; } } CheckModifiers(location, diagnostics); }
// See TypeBind::CheckSingleConstraint. private static bool CheckConstraints( Symbol containingSymbol, ConversionsBase conversions, TypeMap substitution, TypeParameterSymbol typeParameter, TypeSymbol typeArgument, Compilation currentCompilation, ArrayBuilder <TypeParameterDiagnosticInfo> diagnosticsBuilder, ref ArrayBuilder <TypeParameterDiagnosticInfo> useSiteDiagnosticsBuilder) { Debug.Assert(substitution != null); // The type parameters must be original definitions of type parameters from the containing symbol. Debug.Assert(ReferenceEquals(typeParameter.ContainingSymbol, containingSymbol.OriginalDefinition)); if (typeArgument.IsErrorType()) { return(true); } if (typeArgument.IsPointerType() || typeArgument.IsRestrictedType() || typeArgument.SpecialType == SpecialType.System_Void) { // "The type '{0}' may not be used as a type argument" diagnosticsBuilder.Add(new TypeParameterDiagnosticInfo(typeParameter, new CSDiagnosticInfo(ErrorCode.ERR_BadTypeArgument, typeArgument))); return(false); } if (typeArgument.IsStatic) { // "'{0}': static types cannot be used as type arguments" diagnosticsBuilder.Add(new TypeParameterDiagnosticInfo(typeParameter, new CSDiagnosticInfo(ErrorCode.ERR_GenericArgIsStaticClass, typeArgument))); return(false); } if (typeParameter.HasReferenceTypeConstraint && !typeArgument.IsReferenceType) { // "The type '{2}' must be a reference type in order to use it as parameter '{1}' in the generic type or method '{0}'" diagnosticsBuilder.Add(new TypeParameterDiagnosticInfo(typeParameter, new CSDiagnosticInfo(ErrorCode.ERR_RefConstraintNotSatisfied, containingSymbol.ConstructedFrom(), typeParameter, typeArgument))); return(false); } if (typeParameter.HasValueTypeConstraint && !typeArgument.IsNonNullableValueType()) { // "The type '{2}' must be a non-nullable value type in order to use it as parameter '{1}' in the generic type or method '{0}'" diagnosticsBuilder.Add(new TypeParameterDiagnosticInfo(typeParameter, new CSDiagnosticInfo(ErrorCode.ERR_ValConstraintNotSatisfied, containingSymbol.ConstructedFrom(), typeParameter, typeArgument))); return(false); } // The type parameters for a constructed type/method are the type parameters of // the ConstructedFrom type/method, so the constraint types are not substituted. // For instance with "class C<T, U> where T : U", the type parameter for T in "C<object, int>" // has constraint "U", not "int". We need to substitute the constraints from the // original definition of the type parameters using the map from the constructed symbol. var constraintTypes = ArrayBuilder <TypeSymbol> .GetInstance(); HashSet <DiagnosticInfo> useSiteDiagnostics = null; substitution.SubstituteTypesDistinctWithoutModifiers(typeParameter.ConstraintTypesWithDefinitionUseSiteDiagnostics(ref useSiteDiagnostics), constraintTypes); bool hasError = false; foreach (var constraintType in constraintTypes) { if (SatisfiesConstraintType(conversions, typeArgument, constraintType, ref useSiteDiagnostics)) { continue; } ErrorCode errorCode; if (typeArgument.IsReferenceType) { errorCode = ErrorCode.ERR_GenericConstraintNotSatisfiedRefType; } else if (typeArgument.IsNullableType()) { errorCode = constraintType.IsInterfaceType() ? ErrorCode.ERR_GenericConstraintNotSatisfiedNullableInterface : ErrorCode.ERR_GenericConstraintNotSatisfiedNullableEnum; } else if (typeArgument.TypeKind == TypeKind.TypeParameter) { errorCode = ErrorCode.ERR_GenericConstraintNotSatisfiedTyVar; } else { errorCode = ErrorCode.ERR_GenericConstraintNotSatisfiedValType; } SymbolDistinguisher distinguisher = new SymbolDistinguisher(currentCompilation, constraintType, typeArgument); diagnosticsBuilder.Add(new TypeParameterDiagnosticInfo(typeParameter, new CSDiagnosticInfo(errorCode, containingSymbol.ConstructedFrom(), distinguisher.First, typeParameter, distinguisher.Second))); hasError = true; } if (AppendUseSiteDiagnostics(useSiteDiagnostics, typeParameter, ref useSiteDiagnosticsBuilder)) { hasError = true; } constraintTypes.Free(); // Check the constructor constraint. if (typeParameter.HasConstructorConstraint && !SatisfiesConstructorConstraint(typeArgument)) { // "'{2}' must be a non-abstract type with a public parameterless constructor in order to use it as parameter '{1}' in the generic type or method '{0}'" diagnosticsBuilder.Add(new TypeParameterDiagnosticInfo(typeParameter, new CSDiagnosticInfo(ErrorCode.ERR_NewConstraintNotSatisfied, containingSymbol.ConstructedFrom(), typeParameter, typeArgument))); return(false); } return(!hasError); }
protected BoundLocalDeclaration BindVariableDeclaration( LocalDeclarationKind kind, bool isVar, VariableDeclaratorSyntax declarator, TypeSyntax typeSyntax, TypeSymbol declTypeOpt, AliasSymbol aliasOpt, DiagnosticBag diagnostics, CSharpSyntaxNode associatedSyntaxNode = null) { Debug.Assert(declarator != null); Debug.Assert((object)declTypeOpt != null || isVar); Debug.Assert(typeSyntax != null); // if we are not given desired syntax, we use declarator associatedSyntaxNode = associatedSyntaxNode ?? declarator; bool hasErrors = false; BoundExpression initializerOpt; SourceLocalSymbol localSymbol = this.LookupLocal(declarator.Identifier); // In error scenarios with misplaced code, it is possible we can't bind the local declaration. // This occurs through the semantic model. In that case concoct a plausible result. if ((object)localSymbol == null) { localSymbol = SourceLocalSymbol.MakeLocal( ContainingMemberOrLambda as MethodSymbol, this, typeSyntax, declarator.Identifier, declarator.Initializer, LocalDeclarationKind.Variable); } // Check for variable declaration errors. hasErrors |= this.EnsureDeclarationInvariantMeaningInScope(localSymbol, diagnostics); EqualsValueClauseSyntax equalsValueClauseSyntax = declarator.Initializer; if (isVar) { aliasOpt = null; var binder = new ImplicitlyTypedLocalBinder(this, localSymbol); initializerOpt = binder.BindInferredVariableInitializer(diagnostics, equalsValueClauseSyntax, declarator); // If we got a good result then swap the inferred type for the "var" if (initializerOpt != null && (object)initializerOpt.Type != null) { declTypeOpt = initializerOpt.Type; if (declTypeOpt.SpecialType == SpecialType.System_Void) { Error(diagnostics, ErrorCode.ERR_ImplicitlyTypedVariableAssignedBadValue, declarator, declTypeOpt); declTypeOpt = CreateErrorType("var"); hasErrors = true; } if (!declTypeOpt.IsErrorType()) { if (declTypeOpt.IsStatic) { Error(diagnostics, ErrorCode.ERR_VarDeclIsStaticClass, typeSyntax, initializerOpt.Type); hasErrors = true; } } } else { declTypeOpt = CreateErrorType("var"); hasErrors = true; } } else { if (ReferenceEquals(equalsValueClauseSyntax, null)) { initializerOpt = null; } else { // Basically inlined BindVariableInitializer, but with conversion optional. initializerOpt = BindPossibleArrayInitializer(equalsValueClauseSyntax.Value, declTypeOpt, diagnostics); if (kind != LocalDeclarationKind.Fixed) { // If this is for a fixed statement, we'll do our own conversion since there are some special cases. initializerOpt = GenerateConversionForAssignment(declTypeOpt, initializerOpt, diagnostics); } } } Debug.Assert((object)declTypeOpt != null); if (kind == LocalDeclarationKind.Fixed) { // NOTE: this is an error, but it won't prevent further binding. if (isVar) { if (!hasErrors) { Error(diagnostics, ErrorCode.ERR_ImplicitlyTypedLocalCannotBeFixed, declarator); hasErrors = true; } } if (!declTypeOpt.IsPointerType()) { if (!hasErrors) { Error(diagnostics, ErrorCode.ERR_BadFixedInitType, declarator); hasErrors = true; } } else if (!IsValidFixedVariableInitializer(declTypeOpt, localSymbol, ref initializerOpt, diagnostics)) { hasErrors = true; } } if (this.ContainingMemberOrLambda.Kind == SymbolKind.Method && ((MethodSymbol)this.ContainingMemberOrLambda).IsAsync && declTypeOpt.IsRestrictedType()) { Error(diagnostics, ErrorCode.ERR_BadSpecialByRefLocal, typeSyntax, declTypeOpt); hasErrors = true; } DeclareLocalVariable( localSymbol, declarator.Identifier, declTypeOpt); Debug.Assert((object)localSymbol != null); // It is possible that we have a bracketed argument list, like "int x[];" or "int x[123];" // in a non-fixed-size-array declaration . This is a common error made by C++ programmers. // We have already given a good error at parse time telling the user to either make it "fixed" // or to move the brackets to the type. However, we should still do semantic analysis of // the arguments, so that errors in them are discovered, hovering over them in the IDE // gives good results, and so on. var arguments = default(ImmutableArray<BoundExpression>); if (declarator.ArgumentList != null) { var builder = ArrayBuilder<BoundExpression>.GetInstance(); foreach (var argument in declarator.ArgumentList.Arguments) { var boundArgument = BindValue(argument.Expression, diagnostics, BindValueKind.RValue); builder.Add(boundArgument); } arguments = builder.ToImmutableAndFree(); } if (kind == LocalDeclarationKind.Fixed || kind == LocalDeclarationKind.Using) { // CONSIDER: The error message is "you must provide an initializer in a fixed // CONSIDER: or using declaration". The error message could be targetted to // CONSIDER: the actual situation. "you must provide an initializer in a // CONSIDER: 'fixed' declaration." if (initializerOpt == null) { Error(diagnostics, ErrorCode.ERR_FixedMustInit, declarator); hasErrors = true; } } else if (kind == LocalDeclarationKind.Constant && initializerOpt != null) { foreach (var diagnostic in localSymbol.GetConstantValueDiagnostics(initializerOpt)) { diagnostics.Add(diagnostic); hasErrors = true; } } var boundDeclType = new BoundTypeExpression(typeSyntax, aliasOpt, inferredType: isVar, type: declTypeOpt); return new BoundLocalDeclaration(associatedSyntaxNode, localSymbol, boundDeclType, initializerOpt, arguments, hasErrors); }
internal static void AddDelegateMembers( SourceMemberContainerTypeSymbol delegateType, ArrayBuilder <Symbol> symbols, DelegateDeclarationSyntax syntax, DiagnosticBag diagnostics) { Binder binder = delegateType.GetBinder(syntax.ParameterList); RefKind refKind; TypeSyntax returnTypeSyntax = syntax.ReturnType.SkipRef(out refKind); TypeSymbol returnType = binder.BindType(returnTypeSyntax, diagnostics); // reuse types to avoid reporting duplicate errors if missing: var voidType = binder.GetSpecialType(SpecialType.System_Void, diagnostics, syntax); var objectType = binder.GetSpecialType(SpecialType.System_Object, diagnostics, syntax); var intPtrType = binder.GetSpecialType(SpecialType.System_IntPtr, diagnostics, syntax); if (returnType.IsRestrictedType()) { // Method or delegate cannot return type '{0}' diagnostics.Add(ErrorCode.ERR_MethodReturnCantBeRefAny, returnTypeSyntax.Location, returnType); } // A delegate has the following members: (see CLI spec 13.6) // (1) a method named Invoke with the specified signature var invoke = new InvokeMethod(delegateType, refKind, returnType, syntax, binder, diagnostics); invoke.CheckDelegateVarianceSafety(diagnostics); symbols.Add(invoke); // (2) a constructor with argument types (object, System.IntPtr) symbols.Add(new Constructor(delegateType, voidType, objectType, intPtrType, syntax)); if (binder.Compilation.GetSpecialType(SpecialType.System_IAsyncResult).TypeKind != TypeKind.Error && binder.Compilation.GetSpecialType(SpecialType.System_AsyncCallback).TypeKind != TypeKind.Error && // WinRT delegates don't have Begin/EndInvoke methods !delegateType.IsCompilationOutputWinMdObj()) { var iAsyncResultType = binder.GetSpecialType(SpecialType.System_IAsyncResult, diagnostics, syntax); var asyncCallbackType = binder.GetSpecialType(SpecialType.System_AsyncCallback, diagnostics, syntax); // (3) BeginInvoke symbols.Add(new BeginInvokeMethod(invoke, iAsyncResultType, objectType, asyncCallbackType, syntax)); // and (4) EndInvoke methods symbols.Add(new EndInvokeMethod(invoke, iAsyncResultType, syntax)); } if (delegateType.DeclaredAccessibility <= Accessibility.Private) { return; } HashSet <DiagnosticInfo> useSiteDiagnostics = null; if (!delegateType.IsNoMoreVisibleThan(invoke.ReturnType, ref useSiteDiagnostics)) { // Inconsistent accessibility: return type '{1}' is less accessible than delegate '{0}' diagnostics.Add(ErrorCode.ERR_BadVisDelegateReturn, delegateType.Locations[0], delegateType, invoke.ReturnType); } foreach (var parameter in invoke.Parameters) { if (!parameter.Type.IsAtLeastAsVisibleAs(delegateType, ref useSiteDiagnostics)) { // Inconsistent accessibility: parameter type '{1}' is less accessible than delegate '{0}' diagnostics.Add(ErrorCode.ERR_BadVisDelegateParam, delegateType.Locations[0], delegateType, parameter.Type); } } diagnostics.Add(delegateType.Locations[0], useSiteDiagnostics); }
protected override void MethodChecks(DiagnosticBag diagnostics) { var binder = this.DeclaringCompilation. GetBinderFactory(syntaxReferenceOpt.SyntaxTree).GetBinder(ReturnTypeSyntax, GetSyntax(), this); SyntaxToken arglistToken; var signatureBinder = binder.WithAdditionalFlags(BinderFlags.SuppressConstraintChecks); _lazyParameters = ParameterHelpers.MakeParameters( signatureBinder, this, ParameterListSyntax, true, out arglistToken, diagnostics, false); if (arglistToken.Kind() == SyntaxKind.ArgListKeyword) { // This is a parse-time error in the native compiler; it is a semantic analysis error in Roslyn. // error CS1669: __arglist is not valid in this context diagnostics.Add(ErrorCode.ERR_IllegalVarArgs, new SourceLocation(arglistToken)); // Regardless of whether __arglist appears in the source code, we do not mark // the operator method as being a varargs method. } _lazyReturnType = signatureBinder.BindType(ReturnTypeSyntax, diagnostics); if (_lazyReturnType.IsRestrictedType()) { // Method or delegate cannot return type '{0}' diagnostics.Add(ErrorCode.ERR_MethodReturnCantBeRefAny, ReturnTypeSyntax.Location, _lazyReturnType); } if (_lazyReturnType.IsStatic) { // '{0}': static types cannot be used as return types diagnostics.Add(ErrorCode.ERR_ReturnTypeIsStaticClass, ReturnTypeSyntax.Location, _lazyReturnType); } this.SetReturnsVoid(_lazyReturnType.SpecialType == SpecialType.System_Void); // If we have an operator in an interface or static class then we already // have reported that fact as an error. No need to cascade the error further. if (this.ContainingType.IsInterfaceType() || this.ContainingType.IsStatic) { return; } // SPEC: All types referenced in an operator declaration must be at least as accessible // SPEC: as the operator itself. CheckEffectiveAccessibility(_lazyReturnType, _lazyParameters, diagnostics); CheckValueParameters(diagnostics); CheckOperatorSignatures(diagnostics); }
private void TestBinaryIntrinsicSymbol( BinaryOperatorKind op, TypeSymbol leftType, TypeSymbol rightType, CSharpCompilation compilation, SemanticModel semanticModel, ExpressionSyntax node1, ExpressionSyntax node2, ExpressionSyntax node3, ExpressionSyntax node4, ExpressionSyntax node5, ExpressionSyntax node6, ExpressionSyntax node7, ExpressionSyntax node8 ) { SymbolInfo info1 = semanticModel.GetSymbolInfo(node1); HashSet<DiagnosticInfo> useSiteDiagnostics = null; if (info1.Symbol == null) { if (info1.CandidateSymbols.Length == 0) { if (leftType.IsDynamic() || rightType.IsDynamic()) { Assert.True(CandidateReason.LateBound == info1.CandidateReason || CandidateReason.None == info1.CandidateReason); } else { Assert.Equal(CandidateReason.None, info1.CandidateReason); } } else { Assert.Equal(CandidateReason.OverloadResolutionFailure, info1.CandidateReason); foreach (MethodSymbol s in info1.CandidateSymbols) { Assert.Equal(MethodKind.UserDefinedOperator, s.MethodKind); } } } else { Assert.Equal(leftType.IsDynamic() || rightType.IsDynamic() ? CandidateReason.LateBound : CandidateReason.None, info1.CandidateReason); Assert.Equal(0, info1.CandidateSymbols.Length); } var symbol1 = (MethodSymbol)info1.Symbol; var symbol2 = semanticModel.GetSymbolInfo(node2).Symbol; var symbol3 = semanticModel.GetSymbolInfo(node3).Symbol; var symbol4 = semanticModel.GetSymbolInfo(node4).Symbol; var symbol5 = (MethodSymbol)semanticModel.GetSymbolInfo(node5).Symbol; var symbol6 = semanticModel.GetSymbolInfo(node6).Symbol; var symbol7 = semanticModel.GetSymbolInfo(node7).Symbol; var symbol8 = semanticModel.GetSymbolInfo(node8).Symbol; Assert.Equal(symbol1, symbol5); Assert.Equal(symbol2, symbol6); Assert.Equal(symbol3, symbol7); Assert.Equal(symbol4, symbol8); if ((object)symbol1 != null && symbol1.IsImplicitlyDeclared) { Assert.NotSame(symbol1, symbol5); Assert.Equal(symbol1.GetHashCode(), symbol5.GetHashCode()); for (int i = 0; i < 2; i++) { Assert.Equal(symbol1.Parameters[i], symbol5.Parameters[i]); Assert.Equal(symbol1.Parameters[i].GetHashCode(), symbol5.Parameters[i].GetHashCode()); } Assert.NotEqual(symbol1.Parameters[0], symbol5.Parameters[1]); } switch (op) { case BinaryOperatorKind.LogicalAnd: case BinaryOperatorKind.LogicalOr: Assert.Null(symbol1); Assert.Null(symbol2); Assert.Null(symbol3); Assert.Null(symbol4); return; } BinaryOperatorKind result = OverloadResolution.BinopEasyOut.OpKind(op, leftType, rightType); BinaryOperatorSignature signature; bool isDynamic = (leftType.IsDynamic() || rightType.IsDynamic()); if (result == BinaryOperatorKind.Error) { if (leftType.IsDynamic() && !rightType.IsPointerType() && !rightType.IsRestrictedType()) { signature = new BinaryOperatorSignature(op | BinaryOperatorKind.Dynamic, leftType, rightType, leftType); } else if (rightType.IsDynamic() && !leftType.IsPointerType() && !leftType.IsRestrictedType()) { signature = new BinaryOperatorSignature(op | BinaryOperatorKind.Dynamic, leftType, rightType, rightType); } else if ((op == BinaryOperatorKind.Equal || op == BinaryOperatorKind.NotEqual) && leftType.IsReferenceType && rightType.IsReferenceType && (leftType == rightType || compilation.Conversions.ClassifyConversion(leftType, rightType, ref useSiteDiagnostics).IsReference)) { if (leftType.IsDelegateType() && rightType.IsDelegateType()) { Assert.Equal(leftType, rightType); signature = new BinaryOperatorSignature(op | BinaryOperatorKind.Delegate, leftType, // TODO: this feels like a spec violation leftType, // TODO: this feels like a spec violation compilation.GetSpecialType(SpecialType.System_Boolean)); } else if (leftType.SpecialType == SpecialType.System_Delegate && rightType.SpecialType == SpecialType.System_Delegate) { signature = new BinaryOperatorSignature(op | BinaryOperatorKind.Delegate, compilation.GetSpecialType(SpecialType.System_Delegate), compilation.GetSpecialType(SpecialType.System_Delegate), compilation.GetSpecialType(SpecialType.System_Boolean)); } else { signature = new BinaryOperatorSignature(op | BinaryOperatorKind.Object, compilation.ObjectType, compilation.ObjectType, compilation.GetSpecialType(SpecialType.System_Boolean)); } } else if (op == BinaryOperatorKind.Addition && ((leftType.IsStringType() && !rightType.IsPointerType()) || (!leftType.IsPointerType() && rightType.IsStringType()))) { Assert.False(leftType.IsStringType() && rightType.IsStringType()); if (leftType.IsStringType()) { signature = new BinaryOperatorSignature(op | BinaryOperatorKind.String, leftType, compilation.ObjectType, leftType); } else { Assert.True(rightType.IsStringType()); signature = new BinaryOperatorSignature(op | BinaryOperatorKind.String, compilation.ObjectType, rightType, rightType); } } else if (op == BinaryOperatorKind.Addition && (((leftType.IsIntegralType() || leftType.IsCharType()) && rightType.IsPointerType()) || (leftType.IsPointerType() && (rightType.IsIntegralType() || rightType.IsCharType())))) { if (leftType.IsPointerType()) { signature = new BinaryOperatorSignature(op | BinaryOperatorKind.Pointer, leftType, symbol1.Parameters[1].Type, leftType); Assert.True(symbol1.Parameters[1].Type.IsIntegralType()); } else { signature = new BinaryOperatorSignature(op | BinaryOperatorKind.Pointer, symbol1.Parameters[0].Type, rightType, rightType); Assert.True(symbol1.Parameters[0].Type.IsIntegralType()); } } else if (op == BinaryOperatorKind.Subtraction && (leftType.IsPointerType() && (rightType.IsIntegralType() || rightType.IsCharType()))) { signature = new BinaryOperatorSignature(op | BinaryOperatorKind.String, leftType, symbol1.Parameters[1].Type, leftType); Assert.True(symbol1.Parameters[1].Type.IsIntegralType()); } else if (op == BinaryOperatorKind.Subtraction && leftType.IsPointerType() && leftType == rightType) { signature = new BinaryOperatorSignature(op | BinaryOperatorKind.Pointer, leftType, rightType, compilation.GetSpecialType(SpecialType.System_Int64)); } else if ((op == BinaryOperatorKind.Addition || op == BinaryOperatorKind.Subtraction) && leftType.IsEnumType() && (rightType.IsIntegralType() || rightType.IsCharType()) && (result = OverloadResolution.BinopEasyOut.OpKind(op, leftType.EnumUnderlyingType(), rightType)) != BinaryOperatorKind.Error && (signature = compilation.builtInOperators.GetSignature(result)).RightType == leftType.EnumUnderlyingType()) { signature = new BinaryOperatorSignature(signature.Kind | BinaryOperatorKind.EnumAndUnderlying, leftType, signature.RightType, leftType); } else if ((op == BinaryOperatorKind.Addition || op == BinaryOperatorKind.Subtraction) && rightType.IsEnumType() && (leftType.IsIntegralType() || leftType.IsCharType()) && (result = OverloadResolution.BinopEasyOut.OpKind(op, leftType, rightType.EnumUnderlyingType())) != BinaryOperatorKind.Error && (signature = compilation.builtInOperators.GetSignature(result)).LeftType == rightType.EnumUnderlyingType()) { signature = new BinaryOperatorSignature(signature.Kind | BinaryOperatorKind.EnumAndUnderlying, signature.LeftType, rightType, rightType); } else if (op == BinaryOperatorKind.Subtraction && leftType.IsEnumType() && leftType == rightType) { signature = new BinaryOperatorSignature(op | BinaryOperatorKind.Enum, leftType, rightType, leftType.EnumUnderlyingType()); } else if ((op == BinaryOperatorKind.Equal || op == BinaryOperatorKind.NotEqual || op == BinaryOperatorKind.LessThan || op == BinaryOperatorKind.LessThanOrEqual || op == BinaryOperatorKind.GreaterThan || op == BinaryOperatorKind.GreaterThanOrEqual) && leftType.IsEnumType() && leftType == rightType) { signature = new BinaryOperatorSignature(op | BinaryOperatorKind.Enum, leftType, rightType, compilation.GetSpecialType(SpecialType.System_Boolean)); } else if ((op == BinaryOperatorKind.Xor || op == BinaryOperatorKind.And || op == BinaryOperatorKind.Or) && leftType.IsEnumType() && leftType == rightType) { signature = new BinaryOperatorSignature(op | BinaryOperatorKind.Enum, leftType, rightType, leftType); } else if ((op == BinaryOperatorKind.Addition || op == BinaryOperatorKind.Subtraction) && leftType.IsDelegateType() && leftType == rightType) { signature = new BinaryOperatorSignature(op | BinaryOperatorKind.Delegate, leftType, leftType, leftType); } else if ((op == BinaryOperatorKind.Equal || op == BinaryOperatorKind.NotEqual || op == BinaryOperatorKind.LessThan || op == BinaryOperatorKind.LessThanOrEqual || op == BinaryOperatorKind.GreaterThan || op == BinaryOperatorKind.GreaterThanOrEqual) && leftType.IsPointerType() && rightType.IsPointerType()) { signature = new BinaryOperatorSignature(op | BinaryOperatorKind.Pointer, compilation.CreatePointerTypeSymbol(compilation.GetSpecialType(SpecialType.System_Void)), compilation.CreatePointerTypeSymbol(compilation.GetSpecialType(SpecialType.System_Void)), compilation.GetSpecialType(SpecialType.System_Boolean)); } else { if ((object)symbol1 != null) { Assert.False(symbol1.IsImplicitlyDeclared); Assert.Equal(MethodKind.UserDefinedOperator, symbol1.MethodKind); if (leftType.IsValueType && !leftType.IsPointerType()) { if (rightType.IsValueType && !rightType.IsPointerType()) { Assert.Same(symbol1, symbol2); Assert.Same(symbol1, symbol3); Assert.Same(symbol1, symbol4); return; } else { Assert.Null(symbol2); Assert.Same(symbol1, symbol3); Assert.Null(symbol4); return; } } else if (rightType.IsValueType && !rightType.IsPointerType()) { Assert.Null(symbol2); Assert.Null(symbol3); Assert.Same(symbol1, symbol4); return; } else { Assert.Null(symbol2); Assert.Null(symbol3); Assert.Null(symbol4); return; } } Assert.Null(symbol1); Assert.Null(symbol2); if (!rightType.IsDynamic()) { Assert.Null(symbol3); } if (!leftType.IsDynamic()) { Assert.Null(symbol4); } return; } } else if ((op == BinaryOperatorKind.Equal || op == BinaryOperatorKind.NotEqual) && leftType != rightType && (!leftType.IsValueType || !rightType.IsValueType || leftType.SpecialType == SpecialType.System_Boolean || rightType.SpecialType == SpecialType.System_Boolean || (leftType.SpecialType == SpecialType.System_Decimal && (rightType.SpecialType == SpecialType.System_Double || rightType.SpecialType == SpecialType.System_Single)) || (rightType.SpecialType == SpecialType.System_Decimal && (leftType.SpecialType == SpecialType.System_Double || leftType.SpecialType == SpecialType.System_Single))) && (!leftType.IsReferenceType || !rightType.IsReferenceType || !compilation.Conversions.ClassifyConversion(leftType, rightType, ref useSiteDiagnostics).IsReference)) { Assert.Null(symbol1); Assert.Null(symbol2); Assert.Null(symbol3); Assert.Null(symbol4); return; } else { signature = compilation.builtInOperators.GetSignature(result); } Assert.NotNull(symbol1); string containerName = signature.LeftType.ToTestDisplayString(); string leftName = containerName; string rightName = signature.RightType.ToTestDisplayString(); string returnName = signature.ReturnType.ToTestDisplayString(); if (isDynamic) { containerName = compilation.DynamicType.ToTestDisplayString(); } else if (op == BinaryOperatorKind.Addition || op == BinaryOperatorKind.Subtraction) { if (signature.LeftType.IsObjectType() && signature.RightType.IsStringType()) { containerName = rightName; } else if ((leftType.IsEnumType() || leftType.IsPointerType()) && (rightType.IsIntegralType() || rightType.IsCharType())) { containerName = leftType.ToTestDisplayString(); leftName = containerName; returnName = containerName; } else if ((rightType.IsEnumType() || rightType.IsPointerType()) && (leftType.IsIntegralType() || leftType.IsCharType())) { containerName = rightType.ToTestDisplayString(); rightName = containerName; returnName = containerName; } } Assert.Equal(isDynamic, signature.ReturnType.IsDynamic()); string expectedSymbol = String.Format("{4} {0}.{2}({1} left, {3} right)", containerName, leftName, OperatorFacts.BinaryOperatorNameFromOperatorKind(op), rightName, returnName); string actualSymbol = symbol1.ToTestDisplayString(); Assert.Equal(expectedSymbol, actualSymbol); Assert.Equal(MethodKind.BuiltinOperator, symbol1.MethodKind); Assert.True(symbol1.IsImplicitlyDeclared); bool isChecked; switch (op) { case BinaryOperatorKind.Multiplication: case BinaryOperatorKind.Addition: case BinaryOperatorKind.Subtraction: case BinaryOperatorKind.Division: isChecked = isDynamic || symbol1.ContainingSymbol.Kind == SymbolKind.PointerType || symbol1.ContainingType.EnumUnderlyingType().SpecialType.IsIntegralType(); break; default: isChecked = isDynamic; break; } Assert.Equal(isChecked, symbol1.IsCheckedBuiltin); Assert.False(symbol1.IsGenericMethod); Assert.False(symbol1.IsExtensionMethod); Assert.False(symbol1.IsExtern); Assert.False(symbol1.CanBeReferencedByName); Assert.Null(symbol1.DeclaringCompilation); Assert.Equal(symbol1.Name, symbol1.MetadataName); Assert.True(symbol1.ContainingSymbol == symbol1.Parameters[0].Type || symbol1.ContainingSymbol == symbol1.Parameters[1].Type); int match = 0; if (symbol1.ContainingSymbol == symbol1.ReturnType) { match++; } if (symbol1.ContainingSymbol == symbol1.Parameters[0].Type) { match++; } if (symbol1.ContainingSymbol == symbol1.Parameters[1].Type) { match++; } Assert.True(match >= 2); Assert.Equal(0, symbol1.Locations.Length); Assert.Null(symbol1.GetDocumentationCommentId()); Assert.Equal("", symbol1.GetDocumentationCommentXml()); Assert.True(symbol1.HasSpecialName); Assert.True(symbol1.IsStatic); Assert.Equal(Accessibility.Public, symbol1.DeclaredAccessibility); Assert.False(symbol1.HidesBaseMethodsByName); Assert.False(symbol1.IsOverride); Assert.False(symbol1.IsVirtual); Assert.False(symbol1.IsAbstract); Assert.False(symbol1.IsSealed); Assert.Equal(2, symbol1.ParameterCount); Assert.Equal(0, symbol1.Parameters[0].Ordinal); Assert.Equal(1, symbol1.Parameters[1].Ordinal); var otherSymbol = (MethodSymbol)semanticModel.GetSymbolInfo(node1).Symbol; Assert.Equal(symbol1, otherSymbol); if (leftType.IsValueType && !leftType.IsPointerType()) { if (rightType.IsValueType && !rightType.IsPointerType()) { Assert.Equal(symbol1, symbol2); Assert.Equal(symbol1, symbol3); Assert.Equal(symbol1, symbol4); return; } else { Assert.Null(symbol2); if (rightType.IsDynamic()) { Assert.NotEqual(symbol1, symbol3); } else { Assert.Equal(rightType.IsPointerType() ? null : symbol1, symbol3); } Assert.Null(symbol4); return; } } else if (rightType.IsValueType && !rightType.IsPointerType()) { Assert.Null(symbol2); Assert.Null(symbol3); if (leftType.IsDynamic()) { Assert.NotEqual(symbol1, symbol4); } else { Assert.Equal(leftType.IsPointerType() ? null : symbol1, symbol4); } return; } Assert.Null(symbol2); if (rightType.IsDynamic()) { Assert.NotEqual(symbol1, symbol3); } else { Assert.Null(symbol3); } if (leftType.IsDynamic()) { Assert.NotEqual(symbol1, symbol4); } else { Assert.Null(symbol4); } }