diff --git a/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/Conversions.cs b/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/Conversions.cs index 98e6d0fc2435d..9f34b91c4b4ce 100644 --- a/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/Conversions.cs +++ b/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/Conversions.cs @@ -318,6 +318,13 @@ private static Conversion ToConversion(OverloadResolutionResult 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) { diff --git a/src/Compilers/CSharp/Portable/Lowering/LambdaRewriter/LambdaRewriter.cs b/src/Compilers/CSharp/Portable/Lowering/LambdaRewriter/LambdaRewriter.cs index 8e3d3bb7fab1f..2ae4a8f1b4dc5 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LambdaRewriter/LambdaRewriter.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LambdaRewriter/LambdaRewriter.cs @@ -355,6 +355,7 @@ private void MakeFrames(ArrayBuilder 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]) diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/ParameterHelpers.cs b/src/Compilers/CSharp/Portable/Symbols/Source/ParameterHelpers.cs index c3a6fb15bb89f..beb39de4d7538 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/ParameterHelpers.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/ParameterHelpers.cs @@ -329,7 +329,8 @@ private static void ReportParameterErrors( 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); diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceDelegateMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceDelegateMethodSymbol.cs index 8949fc3ed2d2d..5a2e92e7576b0 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceDelegateMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceDelegateMethodSymbol.cs @@ -51,7 +51,7 @@ internal static void AddDelegateMembers( 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); diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberFieldSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberFieldSymbol.cs index 0628f3c447090..1bfb2f5c9a691 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberFieldSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberFieldSymbol.cs @@ -50,7 +50,8 @@ protected void TypeChecks(TypeSymbol type, DiagnosticBag diagnostics) { diagnostics.Add(ErrorCode.ERR_FieldCantHaveVoidType, TypeSyntax.Location); } - else if (type.IsRestrictedType()) + //PROTOTYPE(span): span-like instance fields are allowed in span-like types, for now allow inany struct + else if (type.IsRestrictedType(ignoreSpanLikeTypes: !this.IsStatic && containingType.IsStructType())) { diagnostics.Add(ErrorCode.ERR_FieldCantBeRefAny, TypeSyntax.Location, type); } diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberMethodSymbol.cs index 7f0a1e0ce42ec..9fab9ad81371e 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberMethodSymbol.cs @@ -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)) diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbol.cs index b2d09df8410e8..a25df4812d2a4 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbol.cs @@ -1298,7 +1298,8 @@ internal override void ForceComplete(SourceLocation locationOpt, CancellationTok var conversions = new TypeConversions(this.ContainingAssembly.CorLibrary); this.Type.CheckAllConstraints(conversions, _location, diagnostics); - if (this.Type.IsRestrictedType()) + //PROTOTYPE(span): allow in span-like structs? + if (this.Type.IsRestrictedType(ignoreSpanLikeTypes: !this.IsAutoProperty)) { diagnostics.Add(ErrorCode.ERR_FieldCantBeRefAny, this.CSharpSyntaxNode.Type.Location, this.Type); } diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceUserDefinedOperatorSymbolBase.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceUserDefinedOperatorSymbolBase.cs index 2906a890e9ab8..ffb05eba3d606 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceUserDefinedOperatorSymbolBase.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceUserDefinedOperatorSymbolBase.cs @@ -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); diff --git a/src/Compilers/CSharp/Portable/Symbols/TypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/TypeSymbol.cs index ea5c79a6b760e..32f944d899d1d 100644 --- a/src/Compilers/CSharp/Portable/Symbols/TypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/TypeSymbol.cs @@ -639,6 +639,31 @@ public virtual NamedTypeSymbol TupleUnderlyingType /// internal abstract bool IsManagedType { get; } + //PROTOTYPE(span): this will completely change depending on how span-like types are implemented. + // Span and ReadOnlySpan 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 + /// + /// Returns true if the type is a Span/ReadOnlySpan + /// + 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 diff --git a/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs b/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs index 8741b49294134..d8f08c7b5831a 100644 --- a/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs +++ b/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs @@ -917,9 +917,11 @@ internal static bool IsValidV6SwitchGoverningType(this TypeSymbol type, bool isT /// /// Returns true if the type is one of the restricted types, namely: , /// , or . + /// or a ref-like type. /// #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) diff --git a/src/Compilers/CSharp/Test/Semantic/CSharpCompilerSemanticTest.csproj b/src/Compilers/CSharp/Test/Semantic/CSharpCompilerSemanticTest.csproj index 3fb671de0394c..62ce92fbba0f6 100644 --- a/src/Compilers/CSharp/Test/Semantic/CSharpCompilerSemanticTest.csproj +++ b/src/Compilers/CSharp/Test/Semantic/CSharpCompilerSemanticTest.csproj @@ -133,6 +133,7 @@ + diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/SpanStackSafetyTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/SpanStackSafetyTests.cs new file mode 100644 index 0000000000000..ca1f2e75294fd --- /dev/null +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/SpanStackSafetyTests.cs @@ -0,0 +1,595 @@ +// 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 +{ + /// + /// this place is dedicated to binding related error tests + /// + public class SpanStackSafetyTests : CompilingTestBase + { + private static string spanSource = @" + +namespace System +{ + public struct Span + { + public ref T this[int i] => throw null; + public override int GetHashCode() => 1; + } + + public struct ReadonlySpan + { + 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() { 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(); + object y = new ReadonlySpan(); + } +} +"; + + CSharpCompilation comp = CreateCompilationWithMscorlibAndSpan(text); + + comp.VerifyDiagnostics( + // (8,20): error CS0029: Cannot implicitly convert type 'System.Span' to 'object' + // object x = new Span(); + Diagnostic(ErrorCode.ERR_NoImplicitConv, "new Span()").WithArguments("System.Span", "object").WithLocation(8, 20), + // (9,20): error CS0029: Cannot implicitly convert type 'System.ReadonlySpan' to 'object' + // object y = new ReadonlySpan(); + Diagnostic(ErrorCode.ERR_NoImplicitConv, "new ReadonlySpan()").WithArguments("System.ReadonlySpan", "object").WithLocation(9, 20) + ); + } + + [Fact] + public void LambdaCapturing() + { + var text = @" +using System; + +class Program +{ + // this should be ok + public delegate Span D1(Span arg); + + static void Main() + { + var x = new Span(); + + D1 d = (t)=>t; + x = d(x); + + // error due to capture + Func f = () => x[1]; + } +} +"; + + CSharpCompilation comp = CreateCompilationWithMscorlibAndSpan(text); + + //PROTOTYPE(span): make this bind-time diagnostic? + comp.VerifyEmitDiagnostics( + // (17,29): error CS4013: Instance of type 'Span' cannot be used inside an anonymous function, query expression, iterator block or async method + // Func f = () => x[1]; + Diagnostic(ErrorCode.ERR_SpecialByRefInLambda, "x").WithArguments("System.Span").WithLocation(17, 29) + ); + } + + [Fact] + public void GenericArgsAndConstraints() + { + var text = @" +using System; + +class Program +{ + static void Main() + { + var x = new Span(); + + Func> d = ()=>x; + } + + class C1 where T: Span + { + } +} +"; + + CSharpCompilation comp = CreateCompilationWithMscorlibAndSpan(text); + + //PROTOTYPE(span): make this bind-time diagnostic? + comp.VerifyDiagnostics( + // (13,26): error CS0701: 'Span' 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 where T: Span + Diagnostic(ErrorCode.ERR_BadBoundType, "Span").WithArguments("System.Span").WithLocation(13, 26), + // (10,14): error CS0306: The type 'Span' may not be used as a type argument + // Func> d = ()=>x; + Diagnostic(ErrorCode.ERR_BadTypeArgument, "Span").WithArguments("System.Span").WithLocation(10, 14) + ); + } + + [Fact] + public void Arrays() + { + var text = @" +using System; + +class Program +{ + static void Main() + { + var x = new Span[1]; + + var y = new Span[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' + // var x = new Span[1]; + Diagnostic(ErrorCode.ERR_ArrayElementCantBeRefAny, "Span").WithArguments("System.Span").WithLocation(8, 21), + // (10,21): error CS0611: Array elements cannot be of type 'Span' + // var y = new Span[1,2]; + Diagnostic(ErrorCode.ERR_ArrayElementCantBeRefAny, "Span").WithArguments("System.Span").WithLocation(10, 21) + ); + } + + [Fact] + public void ByrefParam() + { + var text = @" +using System; + +class Program +{ + static void Main() + { + } + + static void M1(ref Span ss) + { + } + + static void M2(out Span ss) + { + } + + // OK + static void M3(in Span ss) + { + } + + // technically ok, but what would you return? + static ref Span M4() => throw null; + + //OK + static ref readonly Span M5() => throw null; +} +"; + + CSharpCompilation comp = CreateCompilationWithMscorlibAndSpan(text); + + comp.VerifyDiagnostics( + // (10,20): error CS1601: Cannot make reference to variable of type 'Span' + // static void M1(ref Span ss) + Diagnostic(ErrorCode.ERR_MethodArgCantBeRefAny, "ref Span ss").WithArguments("System.Span").WithLocation(10, 20), + // (14,20): error CS1601: Cannot make reference to variable of type 'Span' + // static void M2(out Span ss) + Diagnostic(ErrorCode.ERR_MethodArgCantBeRefAny, "out Span ss").WithArguments("System.Span").WithLocation(14, 20) + ); + } + + [Fact] + public void Fields() + { + var text = @" +using System; + +public class Program +{ + static void Main() + { + } + + public static Span fs; + public Span fi; + + public struct S1 + { + //PROTOTYPE(span): instance Span fields in structs are ok for now, - until span-like types can be declared + public static Span fs1; + public Span fi1; + } +} +"; + + CSharpCompilation comp = CreateCompilationWithMscorlibAndSpan(text); + + comp.VerifyDiagnostics( + // (16,23): error CS0610: Field or property cannot be of type 'Span' + // public static Span fs1; + Diagnostic(ErrorCode.ERR_FieldCantBeRefAny, "Span").WithArguments("System.Span").WithLocation(16, 23), + // (10,19): error CS0610: Field or property cannot be of type 'Span' + // public static Span fs; + Diagnostic(ErrorCode.ERR_FieldCantBeRefAny, "Span").WithArguments("System.Span").WithLocation(10, 19), + // (11,12): error CS0610: Field or property cannot be of type 'Span' + // public Span fi; + Diagnostic(ErrorCode.ERR_FieldCantBeRefAny, "Span").WithArguments("System.Span").WithLocation(11, 12) + ); + } + + [Fact] + public void Properties() + { + var text = @" +using System; + +public class Program +{ + static void Main() + { + } + + // valid + public static Span ps => default(Span); + public Span pi => default(Span); + + public Span this[int i] => default(Span); + + // not valid + public static Span aps {get;} + public Span api {get; set;} +} +"; + + CSharpCompilation comp = CreateCompilationWithMscorlibAndSpan(text); + + comp.VerifyDiagnostics( + // (17,19): error CS0610: Field or property cannot be of type 'Span' + // public static Span aps {get;} + Diagnostic(ErrorCode.ERR_FieldCantBeRefAny, "Span").WithArguments("System.Span").WithLocation(17, 19), + // (18,12): error CS0610: Field or property cannot be of type 'Span' + // public Span api {get; set;} + Diagnostic(ErrorCode.ERR_FieldCantBeRefAny, "Span").WithArguments("System.Span").WithLocation(18, 12) + ); + } + + [Fact] + public void Operators() + { + var text = @" +using System; + +public class Program +{ + static void Main() + { + } + + // valid + public static Span operator +(Span x, Program y) => default(Span); + + // invalid (baseline w/ TypedReference) + public static TypedReference operator +(Span 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 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 M1(Span arg) + { + await Task.Yield(); + return 42; + } +} +"; + + CSharpCompilation comp = CreateCompilationWithMscorlibAndSpan(text); + + comp.VerifyDiagnostics( + // (11,48): error CS4012: Parameters or locals of type 'Span' cannot be declared in async methods or lambda expressions. + // public static async Task M1(Span arg) + Diagnostic(ErrorCode.ERR_BadSpecialByRefLocal, "arg").WithArguments("System.Span").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 M1() + { + Span local = default(Span); + + await Task.Yield(); + return 42; + } +} +"; + + CSharpCompilation comp = CreateCompilationWithMscorlibAndSpan(text); + + comp.VerifyDiagnostics( + // (13,9): error CS4012: Parameters or locals of type 'Span' cannot be declared in async methods or lambda expressions. + // Span local = default(Span); + Diagnostic(ErrorCode.ERR_BadSpecialByRefLocal, "Span").WithArguments("System.Span").WithLocation(13, 9), + // (13,19): warning CS0219: The variable 'local' is assigned but its value is never used + // Span local = default(Span); + 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' cannot be declared in async methods or lambda expressions. + // Span local = default(Span); + Diagnostic(ErrorCode.ERR_BadSpecialByRefLocal, "Span").WithArguments("System.Span").WithLocation(13, 9), + // (13,19): warning CS0219: The variable 'local' is assigned but its value is never used + // Span local = default(Span); + 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 M1() + { + // this is ok + TakesSpan(default(Span), 123); + + // this is not ok + TakesSpan(default(Span), await I1()); + + // this is ok + TakesSpan(await I1(), default(Span)); + + return 42; + } + + public static void TakesSpan(Span s, int i) + { + } + + public static void TakesSpan(int i, Span s) + { + } + + public static async Task 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' + // TakesSpan(default(Span), await I1()); + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "await I1()").WithArguments("System.Span") + ); + + comp = CreateCompilationWithMscorlibAndSpan(text, TestOptions.DebugExe); + + comp.VerifyEmitDiagnostics( + // (17,39): error CS4007: 'await' cannot be used in an expression containing the type 'System.Span' + // TakesSpan(default(Span), await I1()); + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "await I1()").WithArguments("System.Span") + ); + } + + [Fact] + public void AsyncSpillTemp() + { + var text = @" +using System; +using System.Threading.Tasks; + +public class Program +{ + static void Main() + { + } + + public static async Task M1() + { + // this is not ok + TakesSpan(s: default(Span), i: await I1()); + + return 42; + } + + public static void TakesSpan(int i, Span s) + { + } + + public static async Task 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' + // TakesSpan(s: default(Span), i: await I1()); + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "await I1()").WithArguments("System.Span").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' + // TakesSpan(s: default(Span), i: await I1()); + Diagnostic(ErrorCode.ERR_ByRefTypeAndAwait, "await I1()").WithArguments("System.Span").WithLocation(14, 45) + ); + } + + [Fact] + public void BaseMethods() + { + var text = @" +using System; + +public class Program +{ + static void Main() + { + // this is ok (overriden) + default(Span).GetHashCode(); + + // this is ok (implicit boxing) + default(Span).GetType(); + + // this is not ok (implicit boxing) + default(Span).ToString(); + } +} +"; + + CSharpCompilation comp = CreateCompilationWithMscorlibAndSpan(text); + + comp.VerifyDiagnostics( + // (12,9): error CS0029: Cannot implicitly convert type 'System.Span' to 'object' + // default(Span).GetType(); + Diagnostic(ErrorCode.ERR_NoImplicitConv, "default(Span)").WithArguments("System.Span", "object").WithLocation(12, 9), + // (15,9): error CS0029: Cannot implicitly convert type 'System.Span' to 'System.ValueType' + // default(Span).ToString(); + Diagnostic(ErrorCode.ERR_NoImplicitConv, "default(Span)").WithArguments("System.Span", "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 d0 = default(TypedReference).GetHashCode; + + // none of the following is ok, since we would need to capture the receiver. + Func d1 = default(Span).GetHashCode; + + Func d2 = default(Span).GetType; + + Func d3 = default(Span).ToString; + } +} +"; + + CSharpCompilation comp = CreateCompilationWithMscorlibAndSpan(text); + + comp.VerifyEmitDiagnostics( + // (12,43): error CS0123: No overload for 'GetHashCode' matches delegate 'Func' + // Func d1 = default(Span).GetHashCode; + Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "GetHashCode").WithArguments("GetHashCode", "System.Func").WithLocation(12, 43), + // (14,44): error CS0123: No overload for 'GetType' matches delegate 'Func' + // Func d2 = default(Span).GetType; + Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "GetType").WithArguments("GetType", "System.Func").WithLocation(14, 44), + // (16,46): error CS0123: No overload for 'ToString' matches delegate 'Func' + // Func d3 = default(Span).ToString; + Diagnostic(ErrorCode.ERR_MethDelegateMismatch, "ToString").WithArguments("ToString", "System.Func").WithLocation(16, 46) + ); + } + } +}