private static CSDiagnosticInfo GetDisabledFeatureDiagnosticInfo( MessageID feature, LanguageVersion availableVersion ) { string?requiredFeature = feature.RequiredFeature(); if (requiredFeature != null) { return(new CSDiagnosticInfo( ErrorCode.ERR_FeatureIsExperimental, feature.Localize(), requiredFeature )); } LanguageVersion requiredVersion = feature.RequiredVersion(); return(requiredVersion == LanguageVersion.Preview.MapSpecifiedToEffectiveVersion() ? new CSDiagnosticInfo(ErrorCode.ERR_FeatureInPreview, feature.Localize()) : new CSDiagnosticInfo( availableVersion.GetErrorCode(), feature.Localize(), new CSharpRequiredLanguageVersion(requiredVersion) )); }
/// <remarks> /// NOTE: we are specifically diverging from dev11 to improve the user experience. /// Since treating the "async" keyword as an identifier in older language /// versions can never result in a correct program, we instead accept it as the a /// keyword regardless of the language version and produce an error if the version /// is insufficient. /// </remarks> protected TNode CheckFeatureAvailability <TNode>(TNode node, MessageID feature, bool forceWarning = false) where TNode : CSharpSyntaxNode { LanguageVersion availableVersion = this.Options.LanguageVersion; if (feature == MessageID.IDS_FeatureModuleAttrLoc) { // There's a special error code for this feature, so handle it separately. return(availableVersion >= LanguageVersion.CSharp2 ? node : this.AddError(node, ErrorCode.WRN_NonECMAFeature, feature.Localize())); } LanguageVersion requiredVersion = feature.RequiredVersion(); if (availableVersion >= requiredVersion) { return(node); } if (!forceWarning) { return(this.AddError(node, availableVersion.GetErrorCode(), feature.Localize(), (int)requiredVersion)); } SyntaxDiagnosticInfo rawInfo = new SyntaxDiagnosticInfo(availableVersion.GetErrorCode(), feature.Localize(), (int)requiredVersion); return(this.AddError(node, ErrorCode.WRN_ErrorOverride, rawInfo, rawInfo.Code)); }
/// <remarks> /// NOTE: we are specifically diverging from dev11 to improve the user experience. /// Since treating the "async" keyword as an identifier in older language /// versions can never result in a correct program, we instead accept it as a /// keyword regardless of the language version and produce an error if the version /// is insufficient. /// </remarks> protected TNode CheckFeatureAvailability <TNode>(TNode node, MessageID feature, bool forceWarning = false) where TNode : GreenNode { LanguageVersion availableVersion = this.Options.LanguageVersion; if (feature == MessageID.IDS_FeatureModuleAttrLoc) { // There's a special error code for this feature, so handle it separately. return(availableVersion >= LanguageVersion.CSharp2 ? node : this.AddError(node, ErrorCode.WRN_NonECMAFeature, feature.Localize())); } if (IsFeatureEnabled(feature)) { return(node); } var featureName = feature.Localize(); var requiredFeature = feature.RequiredFeature(); if (requiredFeature != null) { if (forceWarning) { SyntaxDiagnosticInfo rawInfo = new SyntaxDiagnosticInfo(ErrorCode.ERR_FeatureIsExperimental, featureName, requiredFeature); return(this.AddError(node, ErrorCode.WRN_ErrorOverride, rawInfo, rawInfo.Code)); } return(this.AddError(node, ErrorCode.ERR_FeatureIsExperimental, featureName, requiredFeature)); } else { var requiredVersion = feature.RequiredVersion(); if (forceWarning) { SyntaxDiagnosticInfo rawInfo = new SyntaxDiagnosticInfo(availableVersion.GetErrorCode(), featureName, new CSharpRequiredLanguageVersion(requiredVersion)); return(this.AddError(node, ErrorCode.WRN_ErrorOverride, rawInfo, rawInfo.Code)); } return(this.AddError(node, availableVersion.GetErrorCode(), featureName, new CSharpRequiredLanguageVersion(requiredVersion))); } }
internal static void CheckFeatureAvailability(this MessageID feature, LanguageVersion availableVersion, DiagnosticBag diagnostics, Location errorLocation) { LanguageVersion requiredVersion = feature.RequiredVersion(); if (requiredVersion > availableVersion) { diagnostics.Add(availableVersion.GetErrorCode(), errorLocation, feature.Localize(), new CSharpRequiredLanguageVersion(requiredVersion)); } }
internal static CSDiagnosticInfo GetFeatureAvailabilityDiagnosticInfo(this MessageID feature, CSharpParseOptions options) { LanguageVersion requiredVersion; if (options.IsFeatureEnabled(feature)) { return(null); } string requiredFeature = feature.RequiredFeature(); if (requiredFeature != null) { return(new CSDiagnosticInfo(ErrorCode.ERR_FeatureIsExperimental, feature.Localize(), requiredFeature)); } LanguageVersion availableVersion = options.LanguageVersion; requiredVersion = feature.RequiredVersion(); return(requiredVersion == LanguageVersion.Preview.MapSpecifiedToEffectiveVersion() ? new CSDiagnosticInfo(ErrorCode.ERR_FeatureInPreview, feature.Localize()) : new CSDiagnosticInfo(availableVersion.GetErrorCode(), feature.Localize(), new CSharpRequiredLanguageVersion(requiredVersion))); }
private static void ParseAndResolveReferencePaths(string switchName, string switchValue, string baseDirectory, List<string> builder, MessageID origin, List<Diagnostic> diagnostics) { if (string.IsNullOrEmpty(switchValue)) { Debug.Assert(!string.IsNullOrEmpty(switchName)); AddDiagnostic(diagnostics, ErrorCode.ERR_SwitchNeedsString, MessageID.IDS_PathList.Localize(), switchName); return; } foreach (string path in ParseSeparatedPaths(switchValue)) { string resolvedPath = FileUtilities.ResolveRelativePath(path, baseDirectory); if (resolvedPath == null) { AddDiagnostic(diagnostics, ErrorCode.WRN_InvalidSearchPathDir, path, origin.Localize(), MessageID.IDS_DirectoryHasInvalidPath.Localize()); } else if (!PortableShim.Directory.Exists(resolvedPath)) { AddDiagnostic(diagnostics, ErrorCode.WRN_InvalidSearchPathDir, path, origin.Localize(), MessageID.IDS_DirectoryDoesNotExist.Localize()); } else { builder.Add(resolvedPath); } } }
/// <summary> /// Add an ERR_UnexpectedVariance diagnostic to the diagnostic bag. /// </summary> /// <param name="diagnostics">Diagnostic bag.</param> /// <param name="unsafeTypeParameter">Type parameter that is not variance safe.</param> /// <param name="context">Context in which type is not variance safe (e.g. method).</param> /// <param name="locationProvider">Callback to provide location.</param> /// <param name="locationArg">Callback argument.</param> /// <param name="expectedVariance">Desired variance of type.</param> private static void AddVarianceError <T>( this DiagnosticBag diagnostics, TypeParameterSymbol unsafeTypeParameter, Symbol context, LocationProvider <T> locationProvider, T locationArg, MessageID expectedVariance) where T : Symbol { MessageID actualVariance; switch (unsafeTypeParameter.Variance) { case VarianceKind.In: actualVariance = MessageID.IDS_Contravariant; break; case VarianceKind.Out: actualVariance = MessageID.IDS_Covariant; break; default: Debug.Assert(false, "Unexpected variance " + unsafeTypeParameter.Variance); return; } // Get a location that roughly represents the unsafe type parameter use. // (Typically, the locationProvider will return the location of the entire type // reference rather than the specific type parameter, for instance, returning // "C<T>[]" for "interface I<in T> { C<T>[] F(); }" rather than the type parameter // in "C<T>[]", but that is better than returning the location of T within "I<in T>". var location = locationProvider(locationArg) ?? unsafeTypeParameter.Locations[0]; // CONSIDER: instead of using the same error code for all variance errors, we could use different codes for "requires input-safe", // "requires output-safe", and "requires input-safe and output-safe". This would make the error codes much easier to document and // much more actionable. // UNDONE: related location for use is much more useful diagnostics.Add(ErrorCode.ERR_UnexpectedVariance, location, context, unsafeTypeParameter, actualVariance.Localize(), expectedVariance.Localize()); }
private void ReduceLet(LetClauseSyntax let, QueryTranslationState state, DiagnosticBag diagnostics) { // A query expression with a let clause // from x in e // let y = f // ... // is translated into // from * in ( e ) . Select ( x => new { x , y = f } ) // ... var x = state.rangeVariable; // We use a slightly different translation strategy. We produce // from * in ( e ) . Select ( x => new Pair<X,Y>(x, f) ) // Where X is the type of x, and Y is the type of the expression f. // Subsequently, x (or members of x, if it is a transparent identifier) // are accessed as TRID.Item1 (or members of that), and y is accessed // as TRID.Item2, where TRID is the compiler-generated identifier used // to represent the transparent identifier in the result. LambdaBodyFactory bodyFactory = (LambdaSymbol lambdaSymbol, ref Binder lambdaBodyBinder, DiagnosticBag d) => { var xExpression = new BoundParameter(let, lambdaSymbol.Parameters[0]) { WasCompilerGenerated = true }; var yExpression = lambdaBodyBinder.BindValue(let.Expression, d, BindValueKind.RValue); SourceLocation errorLocation = new SourceLocation(let.SyntaxTree, new TextSpan(let.Identifier.SpanStart, let.Expression.Span.End - let.Identifier.SpanStart)); if (!yExpression.HasAnyErrors && !yExpression.HasExpressionType()) { MessageID id = MessageID.IDS_NULL; if (yExpression.Kind == BoundKind.UnboundLambda) { id = ((UnboundLambda)yExpression).MessageID; } else if (yExpression.Kind == BoundKind.MethodGroup) { id = MessageID.IDS_MethodGroup; } else { Debug.Assert(yExpression.IsLiteralNull(), "How did we successfully bind an expression without a type?"); } Error(d, ErrorCode.ERR_QueryRangeVariableAssignedBadValue, errorLocation, id.Localize()); yExpression = new BoundBadExpression(yExpression.Syntax, LookupResultKind.Empty, ImmutableArray <Symbol> .Empty, ImmutableArray.Create <BoundNode>(yExpression), CreateErrorType()); } else if (!yExpression.HasAnyErrors && yExpression.Type.SpecialType == SpecialType.System_Void) { Error(d, ErrorCode.ERR_QueryRangeVariableAssignedBadValue, errorLocation, yExpression.Type); yExpression = new BoundBadExpression(yExpression.Syntax, LookupResultKind.Empty, ImmutableArray <Symbol> .Empty, ImmutableArray.Create <BoundNode>(yExpression), yExpression.Type); } var construction = MakePair(let, x.Name, xExpression, let.Identifier.ValueText, yExpression, state, d); // The bound block represents a closure scope for transparent identifiers captured in the let clause. // Such closures shall be associated with the lambda body expression. return(lambdaBodyBinder.CreateBlockFromExpression(let.Expression, lambdaBodyBinder.Locals, null, construction, d)); }; var lambda = MakeQueryUnboundLambda(state.RangeVariableMap(), ImmutableArray.Create(x), let.Expression, bodyFactory); state.rangeVariable = state.TransparentRangeVariable(this); state.AddTransparentIdentifier(x.Name); var y = state.AddRangeVariable(this, let.Identifier, diagnostics); state.allRangeVariables[y].Add(let.Identifier.ValueText); var invocation = MakeQueryInvocation(let, state.fromExpression, "Select", lambda, diagnostics); state.fromExpression = MakeQueryClause(let, invocation, y, invocation); }
private void CheckFeatureAvailability(MessageID feature) { var options = this.Options; if (options.IsFeatureEnabled(feature)) { return; } string requiredFeature = feature.RequiredFeature(); if (requiredFeature != null) { if (!options.IsFeatureEnabled(feature)) { this.AddError(ErrorCode.ERR_FeatureIsExperimental, feature.Localize(), requiredFeature); } return; } LanguageVersion availableVersion = this.Options.LanguageVersion; var requiredVersion = feature.RequiredVersion(); if (availableVersion >= requiredVersion) return; var featureName = feature.Localize(); this.AddError(availableVersion.GetErrorCode(), featureName, requiredVersion.Localize()); }
private static void AddVarianceError <T>( this BindingDiagnosticBag diagnostics, TypeParameterSymbol unsafeTypeParameter, Symbol context, LocationProvider <T> locationProvider, T locationArg, MessageID expectedVariance) where T : Symbol { MessageID actualVariance; switch (unsafeTypeParameter.Variance) { case VarianceKind.In: actualVariance = MessageID.IDS_Contravariant; break; case VarianceKind.Out: actualVariance = MessageID.IDS_Covariant; break; default: throw ExceptionUtilities.UnexpectedValue(unsafeTypeParameter.Variance); } // Get a location that roughly represents the unsafe type parameter use. // (Typically, the locationProvider will return the location of the entire type // reference rather than the specific type parameter, for instance, returning // "C<T>[]" for "interface I<in T> { C<T>[] F(); }" rather than the type parameter // in "C<T>[]", but that is better than returning the location of T within "I<in T>". var location = locationProvider(locationArg) ?? unsafeTypeParameter.Locations[0]; // CONSIDER: instead of using the same error code for all variance errors, we could use different codes for "requires input-safe", // "requires output-safe", and "requires input-safe and output-safe". This would make the error codes much easier to document and // much more actionable. // UNDONE: related location for use is much more useful if (!(context is TypeSymbol) && context.IsStatic && !context.IsAbstract && !context.IsVirtual) { diagnostics.Add(ErrorCode.ERR_UnexpectedVarianceStaticMember, location, context, unsafeTypeParameter, actualVariance.Localize(), expectedVariance.Localize(), new CSharpRequiredLanguageVersion(MessageID.IDS_FeatureVarianceSafetyForStaticInterfaceMembers.RequiredVersion())); } else { diagnostics.Add(ErrorCode.ERR_UnexpectedVariance, location, context, unsafeTypeParameter, actualVariance.Localize(), expectedVariance.Localize()); } }
private void CheckFeatureAvailability(MessageID feature) { LanguageVersion availableVersion = this.Options.LanguageVersion; var requiredVersion = feature.RequiredVersion(); if (availableVersion >= requiredVersion) return; var featureName = feature.Localize(); this.AddError(availableVersion.GetErrorCode(), featureName, requiredVersion.Localize()); }