未验证 提交 9df66a1f 编写于 作者: C Charles Stoner 提交者: GitHub

Misc. changes (#28239)

上级 fffa9bed
......@@ -179,5 +179,15 @@ A warning is reported for inconsistent top-level nullability of constraint types
static void F4<T> where T : class, Stream? { } // warning
static void F5<T> where T : Stream?, IDisposable { } // warning
```
An error is reported for duplicate constraints. _Should the error be reported for duplicates that differ by top-level or nested nullability?_
```c#
class C<T> where T : class
{
static void F1<U>() where U : T?, T? { } // error: duplicate constraint
static void F2<U>() where U : I<T?>, I<T?> { } // error: duplicate constraint
static void F3<U>() where U : T, T? { } // error?
static void F4<U>() where U : I<T>, I<T?> { } // error?
}
```
## Compiler switch
_Describe behavior when feature is disabled._
......@@ -101,7 +101,7 @@ internal enum BinderFlags : uint
/// <summary>
/// This is a <see cref="ContextualAttributeBinder"/>, or has <see cref="ContextualAttributeBinder"/> as its parent.
/// </summary>
InContectualAttributeBinder = 1 << 29,
InContextualAttributeBinder = 1 << 29,
// Groups
......
......@@ -209,10 +209,12 @@ internal partial class Binder
return false;
}
// PROTOTYPE(NullableReferenceTypes): Report ERR_DuplicateBound for
// duplicates that differ by top-level or nested nullability as well?
if (constraintTypes.Contains(c => type.Equals(c, TypeCompareKind.AllAspects)))
{
// "Duplicate constraint '{0}' for type parameter '{1}'"
Error(diagnostics, ErrorCode.ERR_DuplicateBound, syntax, type.TypeSymbol, typeParameterName);
Error(diagnostics, ErrorCode.ERR_DuplicateBound, syntax, type, typeParameterName);
return false;
}
......
......@@ -1119,7 +1119,7 @@ private static void CheckRestrictedTypeReceiver(BoundExpression expression, Comp
private bool IsBindingModuleLevelAttribute()
{
if ((this.Flags & BinderFlags.InContectualAttributeBinder) == 0)
if ((this.Flags & BinderFlags.InContextualAttributeBinder) == 0)
{
return false;
}
......
......@@ -2103,7 +2103,7 @@ private AssemblySymbol GetForwardedToAssembly(string fullName, int arity, Diagno
// might require us to examine types forwarded by this assembly, thus binding assembly level
// attributes again. And the cycle continues.
// So, we won't do the analysis in this case, at the expense of better diagnostics.
if ((this.Flags & BinderFlags.InContectualAttributeBinder) != 0)
if ((this.Flags & BinderFlags.InContextualAttributeBinder) != 0)
{
var current = this;
......
......@@ -16,7 +16,7 @@ internal sealed class ContextualAttributeBinder : Binder
/// <param name="enclosing">Next binder in the chain (enclosing).</param>
/// <param name="symbol">Symbol to which the attribute was applied (e.g. a parameter).</param>
public ContextualAttributeBinder(Binder enclosing, Symbol symbol)
: base(enclosing, enclosing.Flags | BinderFlags.InContectualAttributeBinder)
: base(enclosing, enclosing.Flags | BinderFlags.InContextualAttributeBinder)
{
_attributeTarget = symbol;
_attributedMember = GetAttributedMember(symbol);
......
// 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 Microsoft.CodeAnalysis.CSharp.Symbols;
using System.Collections.Immutable;
using System.Diagnostics;
namespace Microsoft.CodeAnalysis.CSharp
{
......@@ -14,32 +12,13 @@ internal class DiagnosticInfoWithSymbols : DiagnosticInfo
internal DiagnosticInfoWithSymbols(ErrorCode errorCode, object[] arguments, ImmutableArray<Symbol> symbols)
: base(CSharp.MessageProvider.Instance, (int)errorCode, arguments)
{
#if DEBUG
AssertArguments(arguments);
#endif
this.Symbols = symbols;
}
internal DiagnosticInfoWithSymbols(bool isWarningAsError, ErrorCode errorCode, object[] arguments, ImmutableArray<Symbol> symbols)
: base(CSharp.MessageProvider.Instance, isWarningAsError, (int)errorCode, arguments)
{
#if DEBUG
AssertArguments(arguments);
#endif
this.Symbols = symbols;
}
#if DEBUG
private static void AssertArguments(object[] arguments)
{
if (arguments != null)
{
foreach (var argument in arguments)
{
Debug.Assert(!(argument is SymbolWithAnnotations));
}
}
}
#endif
}
}
......@@ -171,7 +171,7 @@ public NamespaceSymbolWithAnnotations(NamespaceSymbol namespaceSymbol)
/// A simple class that combines a single type symbol with annotations
/// </summary>
[DebuggerDisplay("{GetDebuggerDisplay(), nq}")]
internal abstract class TypeSymbolWithAnnotations : NamespaceOrTypeSymbolWithAnnotations
internal abstract class TypeSymbolWithAnnotations : NamespaceOrTypeSymbolWithAnnotations, IFormattable
{
internal static readonly SymbolDisplayFormat DebuggerDisplayFormat = new SymbolDisplayFormat(
typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces,
......@@ -342,6 +342,13 @@ public TypeSymbolWithAnnotations AsNullableReferenceTypeIfInferLocalNullability(
public abstract override string ToDisplayString(SymbolDisplayFormat format = null);
internal string GetDebuggerDisplay() => ToDisplayString(DebuggerDisplayFormat);
// PROTOTYPE(NullableReferenceTypes): Remove IFormattable implementation
// if instances should not be used as Diagnostic arguments.
string IFormattable.ToString(string format, IFormatProvider formatProvider)
{
return ToDisplayString(SymbolDisplayFormat.CSharpErrorMessageFormat);
}
public bool Equals(TypeSymbolWithAnnotations other, TypeCompareKind comparison)
{
if (ReferenceEquals(this, other))
......
......@@ -34611,12 +34611,10 @@ class C<V> where V : V?, V? { }
where T3 : class
where U3 : T3, T3?;";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular8);
// PROTOTYPE(NullableReferenceTypes): Report `Duplicate constraint 'V?' ...` rather than `... 'V' ...`.
// (Requires allowing TypeSymbolWithAnnotations as Diagnostic argument.)
comp.VerifyDiagnostics(
// (3,26): error CS0405: Duplicate constraint 'V' for type parameter 'V'
// (3,26): error CS0405: Duplicate constraint 'V?' for type parameter 'V'
// class C<V> where V : V?, V? { }
Diagnostic(ErrorCode.ERR_DuplicateBound, "V?").WithArguments("V", "V").WithLocation(3, 26),
Diagnostic(ErrorCode.ERR_DuplicateBound, "V?").WithArguments("V?", "V").WithLocation(3, 26),
// (3,9): error CS0454: Circular constraint dependency involving 'V' and 'V'
// class C<V> where V : V?, V? { }
Diagnostic(ErrorCode.ERR_CircularConstraint, "V").WithArguments("V", "V").WithLocation(3, 9),
......@@ -34855,6 +34853,40 @@ class C
Diagnostic(ErrorCode.ERR_ConstructedDynamicTypeAsBound, "I<dynamic?>").WithArguments("I<dynamic?>").WithLocation(5, 35));
}
[Fact]
public void DuplicateConstraints()
{
var source =
@"interface I<T> where T : class { }
class C<T> where T : class
{
static void F1<U>() where U : T, T { }
static void F2<U>() where U : T, T? { }
static void F3<U>() where U : T?, T { }
static void F4<U>() where U : T?, T? { }
static void F5<U>() where U : I<T>, I<T> { }
static void F6<U>() where U : I<T>, I<T?> { }
static void F7<U>() where U : I<T?>, I<T> { }
static void F8<U>() where U : I<T?>, I<T?> { }
}";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular8);
// PROTOTYPE(NullableReferenceTypes): Report ERR_DuplicateBound for
// duplicates that differ by top-level or nested nullability as well?
comp.VerifyDiagnostics(
// (4,38): error CS0405: Duplicate constraint 'T' for type parameter 'U'
// static void F1<U>() where U : T, T { }
Diagnostic(ErrorCode.ERR_DuplicateBound, "T").WithArguments("T", "U").WithLocation(4, 38),
// (7,39): error CS0405: Duplicate constraint 'T?' for type parameter 'U'
// static void F4<U>() where U : T?, T? { }
Diagnostic(ErrorCode.ERR_DuplicateBound, "T?").WithArguments("T?", "U").WithLocation(7, 39),
// (8,41): error CS0405: Duplicate constraint 'I<T>' for type parameter 'U'
// static void F5<U>() where U : I<T>, I<T> { }
Diagnostic(ErrorCode.ERR_DuplicateBound, "I<T>").WithArguments("I<T>", "U").WithLocation(8, 41),
// (11,42): error CS0405: Duplicate constraint 'I<T?>' for type parameter 'U'
// static void F8<U>() where U : I<T?>, I<T?> { }
Diagnostic(ErrorCode.ERR_DuplicateBound, "I<T?>").WithArguments("I<T?>", "U").WithLocation(11, 42));
}
[Fact]
public void PartialClassConstraintMismatch()
{
......@@ -35217,12 +35249,10 @@ static void F(object x, object? y)
public void UnannotatedConstraint_01()
{
var source0 =
@"public class A
{
}
public class B<T> where T : A
{
}";
@"public class A1 { }
public class A2<T> { }
public class B1<T> where T : A1 { }
public class B2<T> where T : A2<object> { }";
var comp0 = CreateCompilation(source0, parseOptions: TestOptions.Regular7);
comp0.VerifyDiagnostics();
var ref0 = comp0.EmitToImageReference();
......@@ -35232,25 +35262,30 @@ public class B<T> where T : A
{
static void Main()
{
new B<A?>();
new B<A>();
new B1<A1?>();
new B1<A1>();
new B2<A2<object?>>();
new B2<A2<object>>();
}
}";
var comp = CreateCompilation(source, references: new[] { ref0 }, parseOptions: TestOptions.Regular8);
comp.VerifyDiagnostics();
var typeParameters = comp.GetMember<NamedTypeSymbol>("B1").TypeParameters;
Assert.Equal("A1", typeParameters[0].ConstraintTypesNoUseSiteDiagnostics[0].ToTestDisplayString(true));
typeParameters = comp.GetMember<NamedTypeSymbol>("B2").TypeParameters;
Assert.Equal("A2<System.Object>", typeParameters[0].ConstraintTypesNoUseSiteDiagnostics[0].ToTestDisplayString(true));
}
[Fact]
public void UnannotatedConstraint_02()
{
var source0 =
@"public class A<T>
{
}
public class B<T> where T : A<object>
{
}";
var comp0 = CreateCompilation(source0, parseOptions: TestOptions.Regular7);
@"using System.Runtime.CompilerServices;
public class A1 { }
public class A2<T> { }
[NonNullTypes(false)] public class B1<T, U> where T : A1 where U : A1? { }
[NonNullTypes(false)] public class B2<T, U> where T : A2<object> where U : A2<object?> { }";
var comp0 = CreateCompilation(new[] { source0, NonNullTypesAttributesDefinition }, parseOptions: TestOptions.Regular8);
comp0.VerifyDiagnostics();
var ref0 = comp0.EmitToImageReference();
......@@ -35259,12 +35294,21 @@ public class B<T> where T : A<object>
{
static void Main()
{
new B<A<object?>>();
new B<A<object>>();
new B1<A1, A1?>();
new B1<A1?, A1>();
new B2<A2<object>, A2<object?>>();
new B2<A2<object?>, A2<object>>();
}
}";
var comp = CreateCompilation(source, references: new[] { ref0 }, parseOptions: TestOptions.Regular8);
comp.VerifyDiagnostics();
// PROTOTYPE(NullableReferenceTypes): Should be ~ rather than !.
var typeParameters = comp.GetMember<NamedTypeSymbol>("B1").TypeParameters;
Assert.Equal("A1!", typeParameters[0].ConstraintTypesNoUseSiteDiagnostics[0].ToTestDisplayString(true));
Assert.Equal("A1?", typeParameters[1].ConstraintTypesNoUseSiteDiagnostics[0].ToTestDisplayString(true));
typeParameters = comp.GetMember<NamedTypeSymbol>("B2").TypeParameters;
Assert.Equal("A2<System.Object!>!", typeParameters[0].ConstraintTypesNoUseSiteDiagnostics[0].ToTestDisplayString(true));
Assert.Equal("A2<System.Object?>!", typeParameters[1].ConstraintTypesNoUseSiteDiagnostics[0].ToTestDisplayString(true));
}
[Fact]
......@@ -35288,14 +35332,20 @@ class C
{
static void Main()
{
A<B1>.F(new B1());
A<B2>.F(new B2());
A<B1>.F(null); // warning
A<B2>.F(null); // warning
A<B1?>.F(null);
A<B2?>.F(null);
}
}";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular8, references: new[] { ref0 });
comp.VerifyDiagnostics();
comp.VerifyDiagnostics(
// (7,17): warning CS8625: Cannot convert null literal to non-nullable reference or unconstrained type parameter.
// A<B1>.F(null); // warning
Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(7, 17),
// (8,17): warning CS8625: Cannot convert null literal to non-nullable reference or unconstrained type parameter.
// A<B2>.F(null); // warning
Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(8, 17));
}
[Fact]
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册