提交 c67384de 编写于 作者: V vsadov

Implements the initial set of span-safety checks.

These are mostly the checks dealing with stack-only nature of the Span. With minor difference they follow the same logic as the existing checks for types such as TypedReference.

==== Not in this change:
Defining and detecting span-like types is NYI. For now we just treat any type named "System.Span" and "System.ReadonlySpan" as span-like. This will change.

Some of the checks result in somewhat generaic messages and happen at emit phase. That was ok when the failures were supposed to be rare.
Error clarity is not the goal of this change, but we will examone what errors should say and whether they should be moved to an earlier phase.
上级 7add7ea3
......@@ -318,6 +318,13 @@ private static Conversion ToConversion(OverloadResolutionResult<MethodSymbol> re
return Conversion.NoConversion;
}
//PROTOTYPE(span): generalize to all restricted types or it would be a compat break?
//cannot capture span-like types.
if (!method.IsStatic && methodGroup.Receiver.Type.IsSpanLikeType())
{
return Conversion.NoConversion;
}
if (method.OriginalDefinition.ContainingType.SpecialType == SpecialType.System_Nullable_T &&
!method.IsOverride)
{
......
......@@ -355,6 +355,7 @@ private void MakeFrames(ArrayBuilder<ClosureDebugInfo> closureDebugInfo)
proxies.Add(captured, new CapturedToFrameSymbolReplacement(hoistedField, isReusable: false));
CompilationState.ModuleBuilderOpt.AddSynthesizedDefinition(frame, hoistedField);
//PROTOTYPE(span): move the check to the binding?
if (hoistedField.Type.IsRestrictedType())
{
foreach (CSharpSyntaxNode syntax in _analysis.CapturedVariables[captured])
......
......@@ -329,7 +329,8 @@ internal static class ParameterHelpers
Location loc = parameterSyntax.Identifier.GetNextToken(includeZeroWidth: true).GetLocation(); //could be missing
diagnostics.Add(ErrorCode.ERR_DefaultValueBeforeRequiredValue, loc);
}
else if (parameter.RefKind != RefKind.None && parameter.Type.IsRestrictedType())
else if (parameter.RefKind != RefKind.None &&
parameter.Type.IsRestrictedType(ignoreSpanLikeTypes: parameter.RefKind == RefKind.RefReadOnly))
{
// CS1601: Cannot make reference to variable of type 'System.TypedReference'
diagnostics.Add(ErrorCode.ERR_MethodArgCantBeRefAny, parameterSyntax.Location, parameter.Type);
......
......@@ -51,7 +51,7 @@ protected void InitializeParameters(ImmutableArray<ParameterSymbol> parameters)
var objectType = binder.GetSpecialType(SpecialType.System_Object, diagnostics, syntax);
var intPtrType = binder.GetSpecialType(SpecialType.System_IntPtr, diagnostics, syntax);
if (returnType.IsRestrictedType())
if (returnType.IsRestrictedType(ignoreSpanLikeTypes: true))
{
// Method or delegate cannot return type '{0}'
diagnostics.Add(ErrorCode.ERR_MethodReturnCantBeRefAny, returnTypeSyntax.Location, returnType);
......
......@@ -50,6 +50,7 @@ protected void TypeChecks(TypeSymbol type, DiagnosticBag diagnostics)
{
diagnostics.Add(ErrorCode.ERR_FieldCantHaveVoidType, TypeSyntax.Location);
}
//PROTOTYPE(span): span-like instance fields are allowed in span-like types, for now disallow always
else if (type.IsRestrictedType())
{
diagnostics.Add(ErrorCode.ERR_FieldCantBeRefAny, TypeSyntax.Location, type);
......
......@@ -173,7 +173,8 @@ private void MethodChecks(MethodDeclarationSyntax syntax, Binder withTypeParamsB
var returnTypeSyntax = syntax.ReturnType.SkipRef(out refKind);
_lazyReturnType = signatureBinder.BindType(returnTypeSyntax, diagnostics);
if (_lazyReturnType.IsRestrictedType())
// span-like types are returnable in general
if (_lazyReturnType.IsRestrictedType(ignoreSpanLikeTypes: true))
{
if (_lazyReturnType.SpecialType == SpecialType.System_TypedReference &&
(this.ContainingType.SpecialType == SpecialType.System_TypedReference || this.ContainingType.SpecialType == SpecialType.System_ArgIterator))
......
......@@ -1298,7 +1298,7 @@ internal override void ForceComplete(SourceLocation locationOpt, CancellationTok
var conversions = new TypeConversions(this.ContainingAssembly.CorLibrary);
this.Type.CheckAllConstraints(conversions, _location, diagnostics);
if (this.Type.IsRestrictedType())
if (this.Type.IsRestrictedType(ignoreSpanLikeTypes: !this.IsAutoProperty))
{
diagnostics.Add(ErrorCode.ERR_FieldCantBeRefAny, this.CSharpSyntaxNode.Type.Location, this.Type);
}
......
......@@ -146,7 +146,9 @@ protected override void MethodChecks(DiagnosticBag diagnostics)
_lazyReturnType = signatureBinder.BindType(ReturnTypeSyntax, diagnostics);
if (_lazyReturnType.IsRestrictedType())
// restricted types cannot be returned.
// NOTE: Span-like types can be returned (if expression is returnable).
if (_lazyReturnType.IsRestrictedType(ignoreSpanLikeTypes: true))
{
// Method or delegate cannot return type '{0}'
diagnostics.Add(ErrorCode.ERR_MethodReturnCantBeRefAny, ReturnTypeSyntax.Location, _lazyReturnType);
......
......@@ -639,6 +639,31 @@ public virtual NamedTypeSymbol TupleUnderlyingType
/// </remarks>
internal abstract bool IsManagedType { get; }
//PROTOTYPE(span): this will completely change depending on how span-like types are implemented.
// Span<T> and ReadOnlySpan<T> will be special types (currently they are not always)
// Users may be able to define their own Spanlike types, but that is completely NYI
// For now we will be simply looking at "System.Span" and "System.ReadOnlySpan" names
/// <summary>
/// Returns true if the type is a Span/ReadOnlySpan
/// </summary>
internal bool IsSpanLikeType()
{
var originalDef = this.OriginalDefinition;
if (originalDef.Name != "Span" && originalDef.Name != "ReadonlySpan")
{
return false;
}
var ns = originalDef.ContainingSymbol as NamespaceSymbol;
if (ns?.Name != "System")
{
return false;
}
return (object)ns.ContainingNamespace != null;
}
#region ITypeSymbol Members
INamedTypeSymbol ITypeSymbol.BaseType
......
......@@ -917,9 +917,11 @@ internal static bool IsValidV6SwitchGoverningType(this TypeSymbol type, bool isT
/// <summary>
/// Returns true if the type is one of the restricted types, namely: <see cref="T:System.TypedReference"/>,
/// <see cref="T:System.ArgIterator"/>, or <see cref="T:System.RuntimeArgumentHandle"/>.
/// or a ref-like type.
/// </summary>
#pragma warning restore RS0010
internal static bool IsRestrictedType(this TypeSymbol type)
internal static bool IsRestrictedType(this TypeSymbol type,
bool ignoreSpanLikeTypes = false)
{
// See Dev10 C# compiler, "type.cpp", bool Type::isSpecialByRefType() const
Debug.Assert((object)type != null);
......@@ -930,7 +932,10 @@ internal static bool IsRestrictedType(this TypeSymbol type)
case SpecialType.System_RuntimeArgumentHandle:
return true;
}
return false;
return ignoreSpanLikeTypes?
false:
type.IsSpanLikeType();
}
public static bool IsIntrinsicType(this TypeSymbol type)
......
......@@ -133,6 +133,7 @@
<Compile Include="Semantics\InteractiveUsingTests.cs" />
<Compile Include="Semantics\ScriptSemanticsTests.cs" />
<Compile Include="Semantics\SemanticAnalyzerTests.cs" />
<Compile Include="Semantics\SpanStackSafetyTests.cs" />
<Compile Include="Semantics\SemanticErrorTests.cs" />
<Compile Include="Semantics\StructsTests.cs" />
<Compile Include="Semantics\SuppressAccessibilityChecksTests.cs" />
......
// 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.Globalization;
using System.Linq;
using System.Threading;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Xunit;
namespace Microsoft.CodeAnalysis.CSharp.UnitTests
{
/// <summary>
/// this place is dedicated to binding related error tests
/// </summary>
public class SpanStackSafetyTests : CompilingTestBase
{
private static string spanSource = @"
namespace System
{
public struct Span<T>
{
public ref T this[int i] => throw null;
public override int GetHashCode() => 1;
}
public struct ReadonlySpan<T>
{
public ref readonly T this[int i] => throw null;
public override int GetHashCode() => 2;
}
}
";
//PROTOTYPE(span): this will be updated when rules for defining span are implemented
// most likely we would just pick the actual binary/corlib where
// span lives.
private static CSharpCompilation CreateCompilationWithMscorlibAndSpan(string text, CSharpCompilationOptions options = null)
{
var textWitSpan = new string[] { text, spanSource };
var comp = CreateCompilationWithMscorlib45(
textWitSpan,
references: new List<MetadataReference>() { MscorlibRef_v4_0_30316_17626, SystemCoreRef, CSharpRef },
options: options ?? TestOptions.ReleaseExe);
return comp;
}
[Fact]
public void TrivialBoxing()
{
var text = @"
using System;
class Program
{
static void Main()
{
object x = new Span<int>();
object y = new ReadonlySpan<byte>();
}
}
";
CSharpCompilation comp = CreateCompilationWithMscorlibAndSpan(text);
comp.VerifyDiagnostics(
// (8,20): error CS0029: Cannot implicitly convert type 'System.Span<int>' to 'object'
// object x = new Span<int>();
Diagnostic(ErrorCode.ERR_NoImplicitConv, "new Span<int>()").WithArguments("System.Span<int>", "object").WithLocation(8, 20),
// (9,20): error CS0029: Cannot implicitly convert type 'System.ReadonlySpan<byte>' to 'object'
// object y = new ReadonlySpan<byte>();
Diagnostic(ErrorCode.ERR_NoImplicitConv, "new ReadonlySpan<byte>()").WithArguments("System.ReadonlySpan<byte>", "object").WithLocation(9, 20)
);
}
[Fact]
public void LambdaCapturing()
{
var text = @"
using System;
class Program
{
// this should be ok
public delegate Span<T> D1<T>(Span<T> arg);
static void Main()
{
var x = new Span<int>();
D1<int> d = (t)=>t;
x = d(x);
// error due to capture
Func<int> f = () => x[1];
}
}
";
CSharpCompilation comp = CreateCompilationWithMscorlibAndSpan(text);
//PROTOTYPE(span): make this bind-time diagnostic?
comp.VerifyEmitDiagnostics(
// (17,29): error CS4013: Instance of type 'Span<int>' cannot be used inside an anonymous function, query expression, iterator block or async method
// Func<int> f = () => x[1];
Diagnostic(ErrorCode.ERR_SpecialByRefInLambda, "x").WithArguments("System.Span<int>").WithLocation(17, 29)
);
}
[Fact]
public void GenericArgsAndConstraints()
{
var text = @"
using System;
class Program
{
static void Main()
{
var x = new Span<int>();
Func<Span<int>> d = ()=>x;
}
class C1<T> where T: Span<int>
{
}
}
";
CSharpCompilation comp = CreateCompilationWithMscorlibAndSpan(text);
//PROTOTYPE(span): make this bind-time diagnostic?
comp.VerifyDiagnostics(
// (13,26): error CS0701: 'Span<int>' is not a valid constraint. A type used as a constraint must be an interface, a non-sealed class or a type parameter.
// class C1<T> where T: Span<int>
Diagnostic(ErrorCode.ERR_BadBoundType, "Span<int>").WithArguments("System.Span<int>").WithLocation(13, 26),
// (10,14): error CS0306: The type 'Span<int>' may not be used as a type argument
// Func<Span<int>> d = ()=>x;
Diagnostic(ErrorCode.ERR_BadTypeArgument, "Span<int>").WithArguments("System.Span<int>").WithLocation(10, 14)
);
}
[Fact]
public void Arrays()
{
var text = @"
using System;
class Program
{
static void Main()
{
var x = new Span<int>[1];
var y = new Span<int>[1,2];
}
}
";
CSharpCompilation comp = CreateCompilationWithMscorlibAndSpan(text);
//PROTOTYPE(span): make this bind-time diagnostic?
comp.VerifyDiagnostics(
// (8,21): error CS0611: Array elements cannot be of type 'Span<int>'
// var x = new Span<int>[1];
Diagnostic(ErrorCode.ERR_ArrayElementCantBeRefAny, "Span<int>").WithArguments("System.Span<int>").WithLocation(8, 21),
// (10,21): error CS0611: Array elements cannot be of type 'Span<int>'
// var y = new Span<int>[1,2];
Diagnostic(ErrorCode.ERR_ArrayElementCantBeRefAny, "Span<int>").WithArguments("System.Span<int>").WithLocation(10, 21)
);
}
[Fact]
public void ByrefParam()
{
var text = @"
using System;
class Program
{
static void Main()
{
}
static void M1(ref Span<string> ss)
{
}
static void M2(out Span<string> ss)
{
}
// OK
static void M3(in Span<string> ss)
{
}
// technically ok, but what would you return?
static ref Span<string> M4() => throw null;
//OK
static ref readonly Span<string> M5() => throw null;
}
";
CSharpCompilation comp = CreateCompilationWithMscorlibAndSpan(text);
comp.VerifyDiagnostics(
// (10,20): error CS1601: Cannot make reference to variable of type 'Span<string>'
// static void M1(ref Span<string> ss)
Diagnostic(ErrorCode.ERR_MethodArgCantBeRefAny, "ref Span<string> ss").WithArguments("System.Span<string>").WithLocation(10, 20),
// (14,20): error CS1601: Cannot make reference to variable of type 'Span<string>'
// static void M2(out Span<string> ss)
Diagnostic(ErrorCode.ERR_MethodArgCantBeRefAny, "out Span<string> ss").WithArguments("System.Span<string>").WithLocation(14, 20)
);
}
[Fact]
public void Fields()
{
var text = @"
using System;
public class Program
{
static void Main()
{
}
public static Span<byte> fs;
public Span<int> fi;
public struct S1
{
public static Span<byte> fs;
public static Span<int> fi;
}
}
";
CSharpCompilation comp = CreateCompilationWithMscorlibAndSpan(text);
comp.VerifyDiagnostics(
// (16,23): error CS0610: Field or property cannot be of type 'Span<int>'
// public static Span<int> fi;
Diagnostic(ErrorCode.ERR_FieldCantBeRefAny, "Span<int>").WithArguments("System.Span<int>").WithLocation(16, 23),
// (15,23): error CS0610: Field or property cannot be of type 'Span<byte>'
// public static Span<byte> fs;
Diagnostic(ErrorCode.ERR_FieldCantBeRefAny, "Span<byte>").WithArguments("System.Span<byte>").WithLocation(15, 23),
// (10,19): error CS0610: Field or property cannot be of type 'Span<byte>'
// public static Span<byte> fs;
Diagnostic(ErrorCode.ERR_FieldCantBeRefAny, "Span<byte>").WithArguments("System.Span<byte>"),
// (11,12): error CS0610: Field or property cannot be of type 'Span<int>'
// public Span<int> fi;
Diagnostic(ErrorCode.ERR_FieldCantBeRefAny, "Span<int>").WithArguments("System.Span<int>")
);
}
[Fact]
public void Properties()
{
var text = @"
using System;
public class Program
{
static void Main()
{
}
// valid
public static Span<byte> ps => default(Span<byte>);
public Span<int> pi => default(Span<int>);
public Span<int> this[int i] => default(Span<int>);
// not valid
public static Span<byte> aps {get;}
public Span<int> api {get; set;}
}
";
CSharpCompilation comp = CreateCompilationWithMscorlibAndSpan(text);
comp.VerifyDiagnostics(
// (17,19): error CS0610: Field or property cannot be of type 'Span<byte>'
// public static Span<byte> aps {get;}
Diagnostic(ErrorCode.ERR_FieldCantBeRefAny, "Span<byte>").WithArguments("System.Span<byte>").WithLocation(17, 19),
// (18,12): error CS0610: Field or property cannot be of type 'Span<int>'
// public Span<int> api {get; set;}
Diagnostic(ErrorCode.ERR_FieldCantBeRefAny, "Span<int>").WithArguments("System.Span<int>").WithLocation(18, 12)
);
}
[Fact]
public void Operators()
{
var text = @"
using System;
public class Program
{
static void Main()
{
}
// valid
public static Span<byte> operator +(Span<byte> x, Program y) => default(Span<byte>);
// invalid (baseline w/ TypedReference)
public static TypedReference operator +(Span<int> x, Program y) => default(TypedReference);
}
";
CSharpCompilation comp = CreateCompilationWithMscorlibAndSpan(text);
comp.VerifyDiagnostics(
// (14,19): error CS1599: Method or delegate cannot return type 'TypedReference'
// public static TypedReference operator +(Span<int> x, Program y) => default(TypedReference);
Diagnostic(ErrorCode.ERR_MethodReturnCantBeRefAny, "TypedReference").WithArguments("System.TypedReference").WithLocation(14, 19)
);
}
[Fact]
public void AsyncParams()
{
var text = @"
using System;
using System.Threading.Tasks;
public class Program
{
static void Main()
{
}
public static async Task<int> M1(Span<int> arg)
{
await Task.Yield();
return 42;
}
}
";
CSharpCompilation comp = CreateCompilationWithMscorlibAndSpan(text);
comp.VerifyDiagnostics(
// (11,48): error CS4012: Parameters or locals of type 'Span<int>' cannot be declared in async methods or lambda expressions.
// public static async Task<int> M1(Span<int> arg)
Diagnostic(ErrorCode.ERR_BadSpecialByRefLocal, "arg").WithArguments("System.Span<int>").WithLocation(11, 48)
);
}
[Fact]
public void AsyncLocals()
{
var text = @"
using System;
using System.Threading.Tasks;
public class Program
{
static void Main()
{
}
public static async Task<int> M1()
{
Span<int> local = default(Span<int>);
await Task.Yield();
return 42;
}
}
";
CSharpCompilation comp = CreateCompilationWithMscorlibAndSpan(text);
comp.VerifyDiagnostics(
// (13,9): error CS4012: Parameters or locals of type 'Span<int>' cannot be declared in async methods or lambda expressions.
// Span<int> local = default(Span<int>);
Diagnostic(ErrorCode.ERR_BadSpecialByRefLocal, "Span<int>").WithArguments("System.Span<int>").WithLocation(13, 9),
// (13,19): warning CS0219: The variable 'local' is assigned but its value is never used
// Span<int> local = default(Span<int>);
Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "local").WithArguments("local").WithLocation(13, 19)
);
comp = CreateCompilationWithMscorlibAndSpan(text, TestOptions.DebugExe);
comp.VerifyDiagnostics(
// (13,9): error CS4012: Parameters or locals of type 'Span<int>' cannot be declared in async methods or lambda expressions.
// Span<int> local = default(Span<int>);
Diagnostic(ErrorCode.ERR_BadSpecialByRefLocal, "Span<int>").WithArguments("System.Span<int>").WithLocation(13, 9),
// (13,19): warning CS0219: The variable 'local' is assigned but its value is never used
// Span<int> local = default(Span<int>);
Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "local").WithArguments("local").WithLocation(13, 19)
);
}
[Fact]
public void AsyncSpilling()
{
var text = @"
using System;
using System.Threading.Tasks;
public class Program
{
static void Main()
{
}
public static async Task<int> M1()
{
// this is ok
TakesSpan(default(Span<int>), 123);
// this is not ok
TakesSpan(default(Span<int>), await I1());
// this is ok
TakesSpan(await I1(), default(Span<int>));
return 42;
}
public static void TakesSpan(Span<int> s, int i)
{
}
public static void TakesSpan(int i, Span<int> s)
{
}
public static async Task<int> I1()
{
await Task.Yield();
return 42;
}
}
";
CSharpCompilation comp = CreateCompilationWithMscorlibAndSpan(text);
//PROTOTYPE(span): spilling diagnostics is very hard to detect early.
// it would be uncommon too. Is it ok to do in Emit?
comp.VerifyEmitDiagnostics(
// (17,39): error CS4007: 'await' cannot be used in an expression containing the type 'System.Span<int>'
// TakesSpan(default(Span<int>), await I1());
Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "await I1()").WithArguments("System.Span<int>")
);
comp = CreateCompilationWithMscorlibAndSpan(text, TestOptions.DebugExe);
comp.VerifyEmitDiagnostics(
// (17,39): error CS4007: 'await' cannot be used in an expression containing the type 'System.Span<int>'
// TakesSpan(default(Span<int>), await I1());
Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "await I1()").WithArguments("System.Span<int>")
);
}
[Fact]
public void AsyncSpillTemp()
{
var text = @"
using System;
using System.Threading.Tasks;
public class Program
{
static void Main()
{
}
public static async Task<int> M1()
{
// this is not ok
TakesSpan(s: default(Span<int>), i: await I1());
return 42;
}
public static void TakesSpan(int i, Span<int> s)
{
}
public static async Task<int> I1()
{
await Task.Yield();
return 42;
}
}
";
CSharpCompilation comp = CreateCompilationWithMscorlibAndSpan(text);
//PROTOTYPE(span): spilling diagnostics is very hard to detect early.
// it would be uncommon too. Is it ok to do in Emit?
comp.VerifyEmitDiagnostics(
// (14,45): error CS4007: 'await' cannot be used in an expression containing the type 'System.Span<int>'
// TakesSpan(s: default(Span<int>), i: await I1());
Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "await I1()").WithArguments("System.Span<int>").WithLocation(14, 45)
);
comp = CreateCompilationWithMscorlibAndSpan(text, TestOptions.DebugExe);
//PROTOTYPE(span): spilling diagnostics is very hard to detect early.
// it would be uncommon too. Is it ok to do in Emit?
comp.VerifyEmitDiagnostics(
// (14,45): error CS4007: 'await' cannot be used in an expression containing the type 'System.Span<int>'
// TakesSpan(s: default(Span<int>), i: await I1());
Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "await I1()").WithArguments("System.Span<int>").WithLocation(14, 45)
);
}
[Fact]
public void BaseMethods()
{
var text = @"
using System;
public class Program
{
static void Main()
{
// this is ok (overriden)
default(Span<int>).GetHashCode();
// this is ok (implicit boxing)
default(Span<int>).GetType();
// this is not ok (implicit boxing)
default(Span<int>).ToString();
}
}
";
CSharpCompilation comp = CreateCompilationWithMscorlibAndSpan(text);
comp.VerifyDiagnostics(
// (12,9): error CS0029: Cannot implicitly convert type 'System.Span<int>' to 'object'
// default(Span<int>).GetType();
Diagnostic(ErrorCode.ERR_NoImplicitConv, "default(Span<int>)").WithArguments("System.Span<int>", "object").WithLocation(12, 9),
// (15,9): error CS0029: Cannot implicitly convert type 'System.Span<int>' to 'System.ValueType'
// default(Span<int>).ToString();
Diagnostic(ErrorCode.ERR_NoImplicitConv, "default(Span<int>)").WithArguments("System.Span<int>", "System.ValueType").WithLocation(15, 9)
);
}
[Fact]
public void MethodConversion()
{
var text = @"
using System;
public class Program
{
static void Main()
{
//PROTOTYPE(span): we allow this. Is that because it would be a breaking change?
Func<int> d0 = default(TypedReference).GetHashCode;
// none of the following is ok, since we would need to capture the receiver.
Func<int> d1 = default(Span<int>).GetHashCode;
Func<Type> d2 = default(Span<int>).GetType;
Func<string> d3 = default(Span<int>).ToString;
}
}
";
CSharpCompilation comp = CreateCompilationWithMscorlibAndSpan(text);
comp.VerifyEmitDiagnostics(
// (12,43): error CS0123: No overload for 'GetHashCode' matches delegate 'Func<int>'
// Func<int> d1 = default(Span<int>).GetHashCode;
Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "GetHashCode").WithArguments("GetHashCode", "System.Func<int>").WithLocation(12, 43),
// (14,44): error CS0123: No overload for 'GetType' matches delegate 'Func<Type>'
// Func<Type> d2 = default(Span<int>).GetType;
Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "GetType").WithArguments("GetType", "System.Func<System.Type>").WithLocation(14, 44),
// (16,46): error CS0123: No overload for 'ToString' matches delegate 'Func<string>'
// Func<string> d3 = default(Span<int>).ToString;
Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "ToString").WithArguments("ToString", "System.Func<string>").WithLocation(16, 46)
);
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册