提交 3bbb684a 编写于 作者: V Vladimir Sadov 提交者: GitHub

Merge pull request #22050 from dotnet/features/readonly-ref

Merge features/readonly-ref to master
......@@ -16,5 +16,19 @@
<PropertyGroup>
<!-- Compiler server is not currently supported on CoreCLR -->
<UseSharedCompilation>false</UseSharedCompilation>
<CscToolPath>$(MSBuildThisFileDirectory)..\tools\bincore</CscToolPath>
<CscToolExe Condition="'$(OS)' == 'Windows_NT'">RunCsc.cmd</CscToolExe>
<CscToolExe Condition="'$(OS)' != 'Windows_NT'">RunCsc</CscToolExe>
<VbcToolPath>$(MSBuildThisFileDirectory)..\tools\bincore</VbcToolPath>
<VbcToolExe Condition="'$(OS)' == 'Windows_NT'">RunVbc.cmd</VbcToolExe>
<VbcToolExe Condition="'$(OS)' != 'Windows_NT'">RunVbc</VbcToolExe>
</PropertyGroup>
<!-- If packaged on Windows, the RunCsc and RunVbc scripts may not be marked
executable. If we're not running on Windows, mark them as such, just in case -->
<Target Name="MakeCompilerScriptsExecutable"
Condition="'$(BuildingProject)' == 'true' AND '$(OS)' != 'Windows_NT'"
BeforeTargets="CoreCompile">
<Exec Command="chmod +x &quot;$(CscToolPath)/$(CscToolExe)&quot; &quot;$(VbcToolPath)/$(VbcToolExe)&quot;" />
</Target>
</Project>
......@@ -614,70 +614,6 @@ internal static ObsoleteDiagnosticKind ReportDiagnosticsIfObsoleteInternal(Diagn
return AccessCheck.IsSymbolAccessible(symbol, within, throughTypeOpt, out failedThroughTypeCheck, ref useSiteDiagnostics, basesBeingResolved);
}
/// <summary>
/// Expression lvalue and rvalue requirements.
/// </summary>
internal enum BindValueKind : byte
{
/// <summary>
/// Expression is the RHS of an assignment operation.
/// </summary>
/// <remarks>
/// The following are rvalues: values, variables, null literals, properties
/// and indexers with getters, events. The following are not rvalues:
/// namespaces, types, method groups, anonymous functions.
/// </remarks>
RValue,
/// <summary>
/// Expression is the RHS of an assignment operation
/// and may be a method group.
/// </summary>
RValueOrMethodGroup,
/// <summary>
/// Expression is the LHS of a simple assignment operation.
/// </summary>
Assignment,
/// <summary>
/// Expression is the operand of an increment
/// or decrement operation.
/// </summary>
IncrementDecrement,
/// <summary>
/// Expression is the LHS of a compound assignment
/// operation (such as +=).
/// </summary>
CompoundAssignment,
/// <summary>
/// Expression is passed as a ref or out parameter or assigned to a byref variable.
/// </summary>
RefOrOut,
/// <summary>
/// Expression is the operand of an address-of operation (&amp;).
/// </summary>
AddressOf,
/// <summary>
/// Expression is the receiver of a fixed buffer field access
/// </summary>
FixedReceiver,
/// <summary>
/// Expression is assigned by reference.
/// </summary>
RefAssign,
/// <summary>
/// Expression is returned by reference.
/// </summary>
RefReturn,
}
/// <summary>
/// Report diagnostics that should be reported when using a synthesized attribute.
/// </summary>
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.PooledObjects;
......@@ -93,6 +95,11 @@ internal partial class Binder
return CreateAnonymousFunctionConversion(syntax, source, conversion, isCast, destination, diagnostics);
}
if (conversion.IsStackAlloc)
{
return CreateStackAllocConversion(syntax, source, conversion, isCast, destination, diagnostics);
}
if (conversion.IsTupleLiteralConversion ||
(conversion.IsNullable && conversion.UnderlyingConversions[0].IsTupleLiteralConversion))
{
......@@ -312,6 +319,32 @@ private BoundExpression CreateMethodGroupConversion(SyntaxNode syntax, BoundExpr
return new BoundConversion(syntax, group, conversion, @checked: false, explicitCastInCode: isCast, constantValueOpt: ConstantValue.NotAvailable, type: destination, hasErrors: hasErrors) { WasCompilerGenerated = source.WasCompilerGenerated };
}
private BoundExpression CreateStackAllocConversion(SyntaxNode syntax, BoundExpression source, Conversion conversion, bool isCast, TypeSymbol destination, DiagnosticBag diagnostics)
{
Debug.Assert(conversion.IsStackAlloc);
var boundStackAlloc = (BoundStackAllocArrayCreation)source;
var elementType = boundStackAlloc.ElementType;
TypeSymbol stackAllocType;
switch (conversion.Kind)
{
case ConversionKind.StackAllocToPointerType:
stackAllocType = new PointerTypeSymbol(elementType);
break;
case ConversionKind.StackAllocToSpanType:
stackAllocType = Compilation.GetWellKnownType(WellKnownType.System_Span_T).Construct(elementType);
break;
default:
throw ExceptionUtilities.UnexpectedValue(conversion.Kind);
}
var convertedNode = new BoundConvertedStackAllocExpression(syntax, elementType, boundStackAlloc.Count, stackAllocType, boundStackAlloc.HasErrors);
var underlyingConversion = conversion.UnderlyingConversions.Single();
return CreateConversion(syntax, convertedNode, underlyingConversion, isCast, destination, diagnostics);
}
private BoundExpression CreateTupleLiteralConversion(SyntaxNode syntax, BoundTupleLiteral sourceTuple, Conversion conversion, bool isCast, TypeSymbol destination, DiagnosticBag diagnostics)
{
// We have a successful tuple conversion; rather than producing a separate conversion node
......
......@@ -730,7 +730,7 @@ private static string ExtractDeconstructResultElementName(BoundExpression expres
}
default:
var boundVariable = BindExpression(node, diagnostics, invoked: false, indexed: false);
var checkedVariable = CheckValue(boundVariable, BindValueKind.Assignment, diagnostics);
var checkedVariable = CheckValue(boundVariable, BindValueKind.Assignable, diagnostics);
if (expression == null && checkedVariable.Kind != BoundKind.DiscardExpression)
{
expression = node;
......
......@@ -955,32 +955,39 @@ private static void CheckRestrictedTypeReceiver(BoundExpression expression, Comp
// (i.e. the first argument, if invokedAsExtensionMethod).
var gotError = MemberGroupFinalValidation(receiver, method, expression, diagnostics, invokedAsExtensionMethod);
// Skip building up a new array if the first argument doesn't have to be modified.
ImmutableArray<BoundExpression> args;
if (invokedAsExtensionMethod && !ReferenceEquals(receiver, methodGroup.Receiver))
if (invokedAsExtensionMethod)
{
ArrayBuilder<BoundExpression> builder = ArrayBuilder<BoundExpression>.GetInstance();
BoundExpression receiverArgument;
ParameterSymbol receiverParameter = method.Parameters.First();
// Because the receiver didn't pass through CoerceArguments, we need to apply an appropriate
// conversion here.
Debug.Assert(method.ParameterCount > 0);
Debug.Assert(argsToParams.IsDefault || argsToParams[0] == 0);
BoundExpression convertedReceiver = CreateConversion(receiver, methodResult.Result.ConversionForArg(0), method.Parameters[0].Type, diagnostics);
builder.Add(convertedReceiver);
if ((object)receiver != methodGroup.Receiver)
{
// Because the receiver didn't pass through CoerceArguments, we need to apply an appropriate conversion here.
Debug.Assert(argsToParams.IsDefault || argsToParams[0] == 0);
receiverArgument = CreateConversion(receiver, methodResult.Result.ConversionForArg(0), receiverParameter.Type, diagnostics);
}
else
{
receiverArgument = analyzedArguments.Argument(0);
}
bool first = true;
foreach (BoundExpression arg in analyzedArguments.Arguments)
if (receiverParameter.RefKind == RefKind.Ref)
{
if (first)
{
// Skip the first argument (the receiver), since we added our own.
first = false;
}
else
{
builder.Add(arg);
}
// If this was a ref extension method, receiverArgument must be checked for L-value constraints.
// This helper method will also replace it with a BoundBadExpression if it was invalid.
receiverArgument = CheckValue(receiverArgument, BindValueKind.RefOrOut, diagnostics);
CheckFeatureAvailability(receiverArgument.Syntax, MessageID.IDS_FeatureRefExtensionMethods, diagnostics);
}
else if (receiverParameter.RefKind == RefKind.RefReadOnly)
{
CheckFeatureAvailability(receiverArgument.Syntax, MessageID.IDS_FeatureRefExtensionMethods, diagnostics);
}
ArrayBuilder<BoundExpression> builder = ArrayBuilder<BoundExpression>.GetInstance(analyzedArguments.Arguments.Count);
builder.Add(receiverArgument);
builder.AddRange(analyzedArguments.Arguments.Skip(1));
args = builder.ToImmutableAndFree();
}
else
......@@ -1035,6 +1042,17 @@ private static void CheckRestrictedTypeReceiver(BoundExpression expression, Comp
Debug.Assert(args.IsDefaultOrEmpty || (object)receiver != (object)args[0]);
gotError |= !CheckInvocationArgMixing(
node,
method,
receiver,
method.Parameters,
args,
argRefKinds,
argsToParams,
this.LocalScopeDepth,
diagnostics);
if ((object)delegateTypeOpt != null)
{
return new BoundCall(node, receiver, method, args, argNames, argRefKinds, isDelegateCall: true,
......
......@@ -125,30 +125,36 @@ internal partial class Binder
type = BindType(typeSyntax, diagnostics);
foreach (var modifier in p.Modifiers)
{
SyntaxKind modifierKind = modifier.Kind();
if (modifierKind == SyntaxKind.ThisKeyword)
{
Error(diagnostics, ErrorCode.ERR_ThisInBadContext, modifier);
break;
}
else if (modifierKind == SyntaxKind.RefKeyword)
{
refKind = RefKind.Ref;
allValue = false;
break;
}
else if (modifierKind == SyntaxKind.OutKeyword)
{
refKind = RefKind.Out;
allValue = false;
break;
}
else if (modifierKind == SyntaxKind.ParamsKeyword)
var modKind = modifier.Kind();
switch (modifier.Kind())
{
// This was a parse error in the native compiler;
// it is a semantic analysis error in Roslyn. See comments to
// changeset 1674 for details.
Error(diagnostics, ErrorCode.ERR_IllegalParams, p);
case SyntaxKind.RefKeyword:
refKind = RefKind.Ref;
allValue = false;
break;
case SyntaxKind.OutKeyword:
refKind = RefKind.Out;
allValue = false;
break;
case SyntaxKind.ReadOnlyKeyword:
Debug.Assert(refKind == RefKind.Ref || syntax.HasErrors);
refKind = RefKind.RefReadOnly;
allValue = false;
break;
case SyntaxKind.ParamsKeyword:
// This was a parse error in the native compiler;
// it is a semantic analysis error in Roslyn. See comments to
// changeset 1674 for details.
Error(diagnostics, ErrorCode.ERR_IllegalParams, p);
break;
case SyntaxKind.ThisKeyword:
Error(diagnostics, ErrorCode.ERR_ThisInBadContext, modifier);
break;
}
}
}
......
......@@ -1113,7 +1113,12 @@ internal SingleLookupResult CheckViability(Symbol symbol, int arity, LookupOptio
? ((AliasSymbol)symbol).GetAliasTarget(basesBeingResolved)
: symbol;
if (WrongArity(symbol, arity, diagnose, options, out diagInfo))
// Check for symbols marked with 'Microsoft.CodeAnalysis.Embedded' attribute
if (!this.Compilation.SourceModule.Equals(unwrappedSymbol.ContainingModule) && unwrappedSymbol.IsHiddenByCodeAnalysisEmbeddedAttribute())
{
return LookupResult.Empty();
}
else if (WrongArity(symbol, arity, diagnose, options, out diagInfo))
{
return LookupResult.WrongArity(symbol, diagInfo);
}
......
......@@ -78,7 +78,7 @@ private BoundExpression BindCompoundAssignment(AssignmentExpressionSyntax node,
}
}
if (left.Kind == BoundKind.EventAccess && !CheckEventValueKind((BoundEventAccess)left, BindValueKind.Assignment, diagnostics))
if (left.Kind == BoundKind.EventAccess && !CheckEventValueKind((BoundEventAccess)left, BindValueKind.Assignable, diagnostics))
{
// If we're in a place where the event can be assigned, then continue so that we give errors
// about the types and operator not lining up. Otherwise, just report that the event can't
......@@ -2140,7 +2140,7 @@ internal bool IsNonMoveableVariable(BoundExpression expr, out Symbol accessedLoc
}
var unusedDiagnostics = DiagnosticBag.GetInstance();
bool receiverIsLValue = CheckValueKind(receiver, BindValueKind.AddressOf, unusedDiagnostics);
bool receiverIsLValue = CheckValueKind(receiver.Syntax, receiver, BindValueKind.AddressOf, checkingReceiver: false, diagnostics: unusedDiagnostics);
unusedDiagnostics.Free();
if (!receiverIsLValue)
......@@ -2193,7 +2193,7 @@ internal bool IsNonMoveableVariable(BoundExpression expr, out Symbol accessedLoc
}
case BoundKind.PointerIndirectionOperator: //Covers ->, since the receiver will be one of these.
case BoundKind.PointerElementAccess:
case BoundKind.StackAllocArrayCreation:
case BoundKind.ConvertedStackAllocExpression:
{
return true;
}
......@@ -2475,7 +2475,7 @@ private static BindValueKind GetBinaryAssignmentKind(SyntaxKind kind)
switch (kind)
{
case SyntaxKind.SimpleAssignmentExpression:
return BindValueKind.Assignment;
return BindValueKind.Assignable;
case SyntaxKind.AddAssignmentExpression:
case SyntaxKind.AndAssignmentExpression:
case SyntaxKind.DivideAssignmentExpression:
......@@ -3497,9 +3497,34 @@ private BoundExpression BindNullCoalescingOperator(BinaryExpressionSyntax node,
/// </remarks>
private BoundExpression BindConditionalOperator(ConditionalExpressionSyntax node, DiagnosticBag diagnostics)
{
var whenTrue = node.WhenTrue.CheckAndUnwrapRefExpression(diagnostics, out var whenTrueRefKind);
var whenFalse = node.WhenFalse.CheckAndUnwrapRefExpression(diagnostics, out var whenFalseRefKind);
var isRef = whenTrueRefKind == RefKind.Ref && whenFalseRefKind == RefKind.Ref;
if (!isRef)
{
if (whenFalseRefKind == RefKind.Ref)
{
diagnostics.Add(ErrorCode.ERR_RefConditionalNeedsTwoRefs, whenFalse.GetFirstToken().GetLocation());
}
if (whenTrueRefKind == RefKind.Ref)
{
diagnostics.Add(ErrorCode.ERR_RefConditionalNeedsTwoRefs, whenTrue.GetFirstToken().GetLocation());
}
}
BoundExpression condition = BindBooleanExpression(node.Condition, diagnostics);
BoundExpression trueExpr = BindValue(node.WhenTrue, diagnostics, BindValueKind.RValue);
BoundExpression falseExpr = BindValue(node.WhenFalse, diagnostics, BindValueKind.RValue);
var valKind = BindValueKind.RValue;
if (isRef)
{
valKind |= BindValueKind.RefersToLocation;
}
BoundExpression trueExpr = BindValue(whenTrue, diagnostics, valKind);
BoundExpression falseExpr = BindValue(whenFalse, diagnostics, valKind);
TypeSymbol trueType = trueExpr.Type;
TypeSymbol falseType = falseExpr.Type;
......@@ -3566,6 +3591,21 @@ private BoundExpression BindConditionalOperator(ConditionalExpressionSyntax node
type = bestType;
hasErrors = true;
}
else if (isRef)
{
if (!Conversions.HasIdentityConversion(trueType, falseType))
{
diagnostics.Add(ErrorCode.ERR_RefConditionalDifferentTypes, falseExpr.Syntax.Location, trueType);
type = CreateErrorType();
hasErrors = true;
}
else
{
Debug.Assert(Conversions.HasIdentityConversion(trueType, bestType));
Debug.Assert(Conversions.HasIdentityConversion(falseType, bestType));
type = bestType;
}
}
else
{
trueExpr = GenerateConversionForAssignment(bestType, trueExpr, diagnostics);
......@@ -3585,6 +3625,31 @@ private BoundExpression BindConditionalOperator(ConditionalExpressionSyntax node
}
}
if (!hasErrors && isRef)
{
var currentScope = this.LocalScopeDepth;
// val-escape must agree on both branches.
uint whenTrueEscape = GetValEscape(trueExpr, currentScope);
uint whenFalseEscape = GetValEscape(falseExpr, currentScope);
if (whenTrueEscape != whenFalseEscape)
{
// ask the one with narrower escape, for the wider - hopefully the errors will make the violation easier to fix.
if (whenTrueEscape < whenFalseEscape)
{
CheckValEscape(falseExpr.Syntax, falseExpr, currentScope, whenTrueEscape, checkingReceiver: false, diagnostics: diagnostics);
}
else
{
CheckValEscape(trueExpr.Syntax, trueExpr, currentScope, whenFalseEscape, checkingReceiver: false, diagnostics: diagnostics);
}
diagnostics.Add(ErrorCode.ERR_MismatchedRefEscapeInTernary, node.Location);
hasErrors = true;
}
}
ConstantValue constantValue = null;
if (!hasErrors)
......@@ -3593,7 +3658,7 @@ private BoundExpression BindConditionalOperator(ConditionalExpressionSyntax node
hasErrors = constantValue != null && constantValue.IsBad;
}
return new BoundConditionalOperator(node, condition, trueExpr, falseExpr, constantValue, type, hasErrors);
return new BoundConditionalOperator(node, isRef, condition, trueExpr, falseExpr, constantValue, type, hasErrors);
}
/// <summary>
......
......@@ -1213,6 +1213,18 @@ internal NamedTypeSymbol GetWellKnownType(WellKnownType type, DiagnosticBag diag
return typeSymbol;
}
/// <summary>
/// This is a layer on top of the Compilation version that generates a diagnostic if the well-known
/// type isn't found.
/// </summary>
internal NamedTypeSymbol GetWellKnownType(WellKnownType type, ref HashSet<DiagnosticInfo> useSiteDiagnostics)
{
NamedTypeSymbol typeSymbol = this.Compilation.GetWellKnownType(type);
Debug.Assert((object)typeSymbol != null, "Expect an error type if well-known type isn't found");
HashSetExtensions.InitializeAndAdd(ref useSiteDiagnostics, typeSymbol.GetUseSiteDiagnostic());
return typeSymbol;
}
/// <summary>
/// Retrieves a well-known type member and reports diagnostics.
/// </summary>
......@@ -2068,28 +2080,53 @@ internal static bool CheckFeatureAvailability(SyntaxNode syntax, MessageID featu
internal static bool CheckFeatureAvailability(SyntaxTree tree, MessageID feature, DiagnosticBag diagnostics, Location location)
{
var options = (CSharpParseOptions)tree.Options;
if (options.IsFeatureEnabled(feature))
CSDiagnosticInfo error = GetFeatureAvailabilityDiagnosticInfo(tree, feature);
if (error is null)
{
return true;
}
diagnostics.Add(new CSDiagnostic(error, location));
return false;
}
internal static bool CheckFeatureAvailability(SyntaxNode syntax, MessageID feature, ref HashSet<DiagnosticInfo> useSiteDiagnostics)
{
CSDiagnosticInfo error = GetFeatureAvailabilityDiagnosticInfo(syntax.SyntaxTree, feature);
if (error is null)
{
return true;
}
HashSetExtensions.InitializeAndAdd(ref useSiteDiagnostics, error);
return false;
}
private static CSDiagnosticInfo GetFeatureAvailabilityDiagnosticInfo(SyntaxTree tree, MessageID feature)
{
CSharpParseOptions options = (CSharpParseOptions)tree.Options;
if (options.IsFeatureEnabled(feature))
{
return null;
}
string requiredFeature = feature.RequiredFeature();
if (requiredFeature != null)
{
diagnostics.Add(ErrorCode.ERR_FeatureIsExperimental, location, feature.Localize(), requiredFeature);
return false;
return new CSDiagnosticInfo(ErrorCode.ERR_FeatureIsExperimental, feature.Localize(), requiredFeature);
}
LanguageVersion availableVersion = options.LanguageVersion;
LanguageVersion requiredVersion = feature.RequiredVersion();
if (requiredVersion > availableVersion)
{
diagnostics.Add(availableVersion.GetErrorCode(), location, feature.Localize(), new CSharpRequiredLanguageVersion(requiredVersion));
return false;
return new CSDiagnosticInfo(availableVersion.GetErrorCode(), feature.Localize(), new CSharpRequiredLanguageVersion(requiredVersion));
}
return true;
return null;
}
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Diagnostics;
using Microsoft.CodeAnalysis.CSharp.Symbols;
......@@ -19,34 +20,32 @@ internal bool InUnsafeRegion
get { return this.Flags.Includes(BinderFlags.UnsafeRegion); }
}
/// <returns>True if a diagnostic was reported, or would have been reported if not for
/// the suppress flag.</returns>
private bool ReportUnsafeIfNotAllowed(SyntaxNode node, DiagnosticBag diagnostics)
{
return ReportUnsafeIfNotAllowed(node, null, diagnostics);
}
/// <returns>True if a diagnostic was reported, or would have been reported if not for
/// the suppress flag.</returns>
private bool ReportUnsafeIfNotAllowed(SyntaxNode node, TypeSymbol sizeOfTypeOpt, DiagnosticBag diagnostics)
/// <returns>True if a diagnostic was reported</returns>
internal bool ReportUnsafeIfNotAllowed(SyntaxNode node, DiagnosticBag diagnostics, TypeSymbol sizeOfTypeOpt = null)
{
Debug.Assert((node.Kind() == SyntaxKind.SizeOfExpression) == ((object)sizeOfTypeOpt != null), "Should have a type for (only) sizeof expressions.");
return ReportUnsafeIfNotAllowed(node.Location, sizeOfTypeOpt, diagnostics);
return ReportUnsafeIfNotAllowed(node.Location, diagnostics, sizeOfTypeOpt);
}
/// <returns>True if a diagnostic was reported, or would have been reported if not for
/// the suppress flag.</returns>
internal bool ReportUnsafeIfNotAllowed(Location location, DiagnosticBag diagnostics)
/// <returns>True if a diagnostic was reported</returns>
internal bool ReportUnsafeIfNotAllowed(Location location, ref HashSet<DiagnosticInfo> useSiteDiagnostics, TypeSymbol sizeOfTypeOpt = null)
{
return ReportUnsafeIfNotAllowed(location, sizeOfTypeOpt: null, diagnostics: diagnostics);
var diagnosticInfo = GetUnsafeDiagnosticInfo(sizeOfTypeOpt: sizeOfTypeOpt);
if (diagnosticInfo is null)
{
return false;
}
HashSetExtensions.InitializeAndAdd(ref useSiteDiagnostics, diagnosticInfo);
return true;
}
/// <returns>True if a diagnostic was reported, or would have been reported if not for
/// the suppress flag.</returns>
private bool ReportUnsafeIfNotAllowed(Location location, TypeSymbol sizeOfTypeOpt, DiagnosticBag diagnostics)
/// <returns>True if a diagnostic was reported</returns>
internal bool ReportUnsafeIfNotAllowed(Location location, DiagnosticBag diagnostics, TypeSymbol sizeOfTypeOpt = null)
{
var diagnosticInfo = GetUnsafeDiagnosticInfo(sizeOfTypeOpt);
if (diagnosticInfo == null || this.Flags.Includes(BinderFlags.SuppressUnsafeDiagnostics))
if (diagnosticInfo == null)
{
return false;
}
......@@ -57,7 +56,11 @@ private bool ReportUnsafeIfNotAllowed(Location location, TypeSymbol sizeOfTypeOp
private CSDiagnosticInfo GetUnsafeDiagnosticInfo(TypeSymbol sizeOfTypeOpt)
{
if (this.IsIndirectlyInIterator)
if (this.Flags.Includes(BinderFlags.SuppressUnsafeDiagnostics))
{
return null;
}
else if (this.IsIndirectlyInIterator)
{
// Spec 8.2: "An iterator block always defines a safe context, even when its declaration
// is nested in an unsafe context."
......
......@@ -42,6 +42,8 @@ protected override LocalFunctionSymbol LookupLocalFunction(SyntaxToken nameToken
return null;
}
internal override uint LocalScopeDepth => Binder.ExternalScope;
internal override bool IsAccessibleHelper(Symbol symbol, TypeSymbol accessThroughType, out bool failedThroughTypeCheck, ref HashSet<DiagnosticInfo> useSiteDiagnostics, ConsList<Symbol> basesBeingResolved)
{
failedThroughTypeCheck = false;
......
......@@ -327,12 +327,12 @@ private BoundForEachStatement BindForEachPartsWorker(DiagnosticBag diagnostics,
ImmutableArray<MethodSymbol> originalUserDefinedConversions = elementConversion.OriginalUserDefinedConversions;
if (originalUserDefinedConversions.Length > 1)
{
diagnostics.Add(ErrorCode.ERR_AmbigUDConv, _syntax.ForEachKeyword.GetLocation(), originalUserDefinedConversions[0], originalUserDefinedConversions[1], inferredType, iterationVariableType);
diagnostics.Add(ErrorCode.ERR_AmbigUDConv, foreachKeyword.GetLocation(), originalUserDefinedConversions[0], originalUserDefinedConversions[1], inferredType, iterationVariableType);
}
else
{
SymbolDistinguisher distinguisher = new SymbolDistinguisher(this.Compilation, inferredType, iterationVariableType);
diagnostics.Add(ErrorCode.ERR_NoExplicitConv, _syntax.ForEachKeyword.GetLocation(), distinguisher.First, distinguisher.Second);
diagnostics.Add(ErrorCode.ERR_NoExplicitConv, foreachKeyword.GetLocation(), distinguisher.First, distinguisher.Second);
}
hasErrors = true;
}
......@@ -347,7 +347,16 @@ private BoundForEachStatement BindForEachPartsWorker(DiagnosticBag diagnostics,
builder.CollectionConversion = this.Conversions.ClassifyConversionFromExpression(collectionExpr, builder.CollectionType, ref useSiteDiagnostics);
builder.CurrentConversion = this.Conversions.ClassifyConversionFromType(builder.CurrentPropertyGetter.ReturnType, builder.ElementType, ref useSiteDiagnostics);
builder.EnumeratorConversion = this.Conversions.ClassifyConversionFromType(builder.GetEnumeratorMethod.ReturnType, GetSpecialType(SpecialType.System_Object, diagnostics, _syntax), ref useSiteDiagnostics);
var getEnumeratorType = builder.GetEnumeratorMethod.ReturnType;
// we never convert struct enumerators to object - it is done only for null-checks.
builder.EnumeratorConversion = getEnumeratorType.IsValueType?
Conversion.Identity:
this.Conversions.ClassifyConversionFromType(getEnumeratorType, GetSpecialType(SpecialType.System_Object, diagnostics, _syntax), ref useSiteDiagnostics);
if (getEnumeratorType.IsRestrictedType() && (IsDirectlyInIterator || IsInAsyncMethod()))
{
diagnostics.Add(ErrorCode.ERR_BadSpecialByRefIterator, foreachKeyword.GetLocation(), getEnumeratorType);
}
diagnostics.Add(_syntax.ForEachKeyword.GetLocation(), useSiteDiagnostics);
......
......@@ -239,5 +239,7 @@ protected override LocalFunctionSymbol LookupLocalFunction(SyntaxToken nameToken
{
return null;
}
internal override uint LocalScopeDepth => Binder.ExternalScope;
}
}
......@@ -63,6 +63,8 @@ protected override LocalFunctionSymbol LookupLocalFunction(SyntaxToken nameToken
return null;
}
internal override uint LocalScopeDepth => Binder.TopLevelScope;
internal override Symbol ContainingMemberOrLambda
{
get
......
......@@ -16,6 +16,7 @@ internal partial class LocalScopeBinder : Binder
private ImmutableArray<LocalSymbol> _locals;
private ImmutableArray<LocalFunctionSymbol> _localFunctions;
private ImmutableArray<LabelSymbol> _labels;
private readonly uint _localScopeDepth;
internal LocalScopeBinder(Binder next)
: this(next, next.Flags)
......@@ -25,6 +26,35 @@ internal LocalScopeBinder(Binder next)
internal LocalScopeBinder(Binder next, BinderFlags flags)
: base(next, flags)
{
var parentDepth = next.LocalScopeDepth;
if (parentDepth != Binder.TopLevelScope)
{
_localScopeDepth = parentDepth + 1;
}
else
{
//NOTE: TopLevel is special.
//For our purpose parameters and top level locals are on that level.
var parentScope = next;
while(parentScope != null)
{
if (parentScope is InMethodBinder || parentScope is WithLambdaParametersBinder)
{
_localScopeDepth = Binder.TopLevelScope;
break;
}
if (parentScope is LocalScopeBinder)
{
_localScopeDepth = Binder.TopLevelScope + 1;
break;
}
parentScope = parentScope.Next;
Debug.Assert(parentScope != null);
}
}
}
internal sealed override ImmutableArray<LocalSymbol> Locals
......@@ -338,6 +368,8 @@ protected override LocalFunctionSymbol LookupLocalFunction(SyntaxToken nameToken
return base.LookupLocalFunction(nameToken);
}
internal override uint LocalScopeDepth => _localScopeDepth;
internal override void LookupSymbolsInSingleBinder(
LookupResult result, string name, int arity, ConsList<Symbol> basesBeingResolved, LookupOptions options, Binder originalBinder, bool diagnose, ref HashSet<DiagnosticInfo> useSiteDiagnostics)
{
......
......@@ -158,6 +158,11 @@ internal static SingleLookupResult WrongArity(Symbol symbol, DiagnosticInfo erro
return new SingleLookupResult(LookupResultKind.WrongArity, symbol, error);
}
internal static SingleLookupResult Empty()
{
return new SingleLookupResult(LookupResultKind.Empty, null, null);
}
internal static SingleLookupResult NotReferencable(Symbol symbol, DiagnosticInfo error)
{
return new SingleLookupResult(LookupResultKind.NotReferencable, symbol, error);
......
......@@ -260,6 +260,15 @@ private static class ConversionSingletons
internal static ImmutableArray<Conversion> PointerToIntegerUnderlying = ImmutableArray.Create(PointerToInteger);
}
internal static Conversion MakeStackAllocToPointerType(Conversion underlyingConversion)
{
return new Conversion(ConversionKind.StackAllocToPointerType, ImmutableArray.Create(underlyingConversion));
}
internal static Conversion MakeStackAllocToSpanType(Conversion underlyingConversion)
{
return new Conversion(ConversionKind.StackAllocToSpanType, ImmutableArray.Create(underlyingConversion));
}
internal static Conversion MakeNullableConversion(ConversionKind kind, Conversion nestedConversion)
{
......@@ -449,6 +458,17 @@ public bool IsIdentity
}
}
/// <summary>
/// Returns true if the conversion is a stackalloc conversion.
/// </summary>
public bool IsStackAlloc
{
get
{
return Kind == ConversionKind.StackAllocToPointerType || Kind == ConversionKind.StackAllocToSpanType;
}
}
/// <summary>
/// Returns true if the conversion is an implicit numeric conversion or explicit numeric conversion.
/// </summary>
......
......@@ -43,6 +43,8 @@ internal enum ConversionKind : byte
IntPtr,
InterpolatedString, // a conversion from an interpolated string to IFormattable or FormattableString
Deconstruction, // The Deconstruction conversion is not part of the language, it is an implementation detail
StackAllocToPointerType,
StackAllocToSpanType,
// IdentityValue is not a part of the language.
// It is used by lowering to ensure that trivially reduced expressions
......
......@@ -42,6 +42,8 @@ public static bool IsImplicitConversion(this ConversionKind conversionKind)
case ConversionKind.NullToPointer:
case ConversionKind.InterpolatedString:
case ConversionKind.Deconstruction:
case ConversionKind.StackAllocToPointerType:
case ConversionKind.StackAllocToSpanType:
return true;
case ConversionKind.ExplicitNumeric:
......
......@@ -256,6 +256,12 @@ private static Conversion ToConversion(OverloadResolutionResult<MethodSymbol> re
return Conversion.NoConversion;
}
//cannot capture span-like types.
if (!method.IsStatic && methodGroup.Receiver.Type.IsByRefLikeType)
{
return Conversion.NoConversion;
}
if (method.OriginalDefinition.ContainingType.SpecialType == SpecialType.System_Nullable_T &&
!method.IsOverride)
{
......@@ -277,5 +283,43 @@ private static Conversion ToConversion(OverloadResolutionResult<MethodSymbol> re
return new Conversion(ConversionKind.MethodGroup, method, methodGroup.IsExtensionMethodGroup);
}
public override Conversion GetStackAllocConversion(BoundStackAllocArrayCreation sourceExpression, TypeSymbol destination, ref HashSet<DiagnosticInfo> useSiteDiagnostics)
{
if (sourceExpression.Syntax.IsVariableDeclarationInitialization())
{
Debug.Assert((object)sourceExpression.Type == null);
Debug.Assert(sourceExpression.ElementType != null);
var pointerConversion = default(Conversion);
var sourceAsPointer = new PointerTypeSymbol(sourceExpression.ElementType);
pointerConversion = ClassifyImplicitConversionFromType(sourceAsPointer, destination, ref useSiteDiagnostics);
if (pointerConversion.IsValid)
{
// Report unsafe errors
_binder.ReportUnsafeIfNotAllowed(sourceExpression.Syntax.Location, ref useSiteDiagnostics);
return Conversion.MakeStackAllocToPointerType(pointerConversion);
}
else
{
var spanType = _binder.GetWellKnownType(WellKnownType.System_Span_T, ref useSiteDiagnostics).Construct(sourceExpression.ElementType);
var spanConversion = ClassifyImplicitConversionFromType(spanType, destination, ref useSiteDiagnostics);
if (spanConversion.Exists)
{
// Report errors if Span ctor is missing, or using an older C# version
Binder.CheckFeatureAvailability(sourceExpression.Syntax, MessageID.IDS_FeatureRefStructs, ref useSiteDiagnostics);
Binder.GetWellKnownTypeMember(_binder.Compilation, WellKnownMember.System_Span_T__ctor, out DiagnosticInfo memberDiagnosticInfo);
HashSetExtensions.InitializeAndAdd(ref useSiteDiagnostics, memberDiagnosticInfo);
return Conversion.MakeStackAllocToSpanType(spanConversion);
}
}
}
return Conversion.NoConversion;
}
}
}
......@@ -27,6 +27,8 @@ protected ConversionsBase(AssemblySymbol corLibrary, int currentRecursionDepth)
public abstract Conversion GetMethodGroupConversion(BoundMethodGroup source, TypeSymbol destination, ref HashSet<DiagnosticInfo> useSiteDiagnostics);
public abstract Conversion GetStackAllocConversion(BoundStackAllocArrayCreation sourceExpression, TypeSymbol destination, ref HashSet<DiagnosticInfo> useSiteDiagnostics);
protected abstract ConversionsBase CreateInstance(int currentRecursionDepth);
protected abstract Conversion GetInterpolatedStringConversion(BoundInterpolatedString source, TypeSymbol destination, ref HashSet<DiagnosticInfo> useSiteDiagnostics);
......@@ -837,6 +839,14 @@ private Conversion ClassifyImplicitBuiltInConversionFromExpression(BoundExpressi
}
break;
case BoundKind.StackAllocArrayCreation:
var stackAllocConversion = GetStackAllocConversion((BoundStackAllocArrayCreation)sourceExpression, destination, ref useSiteDiagnostics);
if (stackAllocConversion.Exists)
{
return stackAllocConversion;
}
break;
case BoundKind.ThrowExpression:
return Conversion.ImplicitThrow;
}
......
......@@ -30,6 +30,12 @@ public override Conversion GetMethodGroupConversion(BoundMethodGroup source, Typ
throw ExceptionUtilities.Unreachable;
}
public override Conversion GetStackAllocConversion(BoundStackAllocArrayCreation sourceExpression, TypeSymbol destination, ref HashSet<DiagnosticInfo> useSiteDiagnostics)
{
// Conversions involving stackalloc expressions require a Binder.
throw ExceptionUtilities.Unreachable;
}
protected override Conversion GetInterpolatedStringConversion(BoundInterpolatedString source, TypeSymbol destination, ref HashSet<DiagnosticInfo> useSiteDiagnostics)
{
// Conversions involving interpolated strings require a Binder.
......
......@@ -169,5 +169,7 @@ internal override ImmutableArray<LocalFunctionSymbol> GetDeclaredLocalFunctionsF
{
throw ExceptionUtilities.Unreachable;
}
internal override uint LocalScopeDepth => Binder.TopLevelScope;
}
}
......@@ -399,7 +399,7 @@
<Node Name="BoundConditionalOperator" Base="BoundExpression">
<!-- Non-null type is required for this node kind -->
<Field Name="Type" Type="TypeSymbol" Override="true" Null="disallow"/>
<Field Name="IsByRef" Type="bool"/>
<Field Name="Condition" Type="BoundExpression"/>
<Field Name="Consequence" Type="BoundExpression"/>
<Field Name="Alternative" Type="BoundExpression"/>
......@@ -1436,9 +1436,13 @@
</Node>
<Node Name="BoundStackAllocArrayCreation" Base="BoundExpression">
<Field Name="ElementType" Type="TypeSymbol" Null="disallow"/>
<Field Name="Count" Type="BoundExpression"/>
</Node>
<Node Name="BoundConvertedStackAllocExpression" Base="BoundStackAllocArrayCreation">
<!-- Non-null type is required for this node kind -->
<Field Name="Type" Type="TypeSymbol" Override="true" Null="disallow"/>
<Field Name="Count" Type="BoundExpression"/>
</Node>
<Node Name="BoundFieldAccess" Base="BoundExpression">
......
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册