Beispiel #1
0
        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)
                       ));
        }
Beispiel #2
0
        /// <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));
        }
Beispiel #3
0
        /// <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)));
            }
        }
Beispiel #4
0
        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));
            }
        }
Beispiel #5
0
        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)));
        }
Beispiel #6
0
        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);
                }
            }
        }
Beispiel #7
0
        /// <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());
        }
Beispiel #8
0
        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);
        }
Beispiel #9
0
        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());
        }
Beispiel #10
0
        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());
            }
        }
Beispiel #11
0
 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());
 }