Use Compiltation to thread through nullability

The work for generic `unmanaged struct` constraints ended up threading
through the correct `Compilation` object in many of the cases where I
was using `Compilation` to calculate whether or not nullability needed
to be checked for constraints. Used that whenever possible.
上级 7a7f65d4
...@@ -578,7 +578,6 @@ private void Validate() ...@@ -578,7 +578,6 @@ private void Validate()
var corLibrary = _compilation.SourceAssembly.CorLibrary; var corLibrary = _compilation.SourceAssembly.CorLibrary;
var conversions = new TypeConversions(corLibrary); var conversions = new TypeConversions(corLibrary);
bool includeNullability = _compilation.IsFeatureEnabled(MessageID.IDS_FeatureNullableReferenceTypes);
foreach (var @using in Usings) foreach (var @using in Usings)
{ {
// Check if `using static` directives meet constraints. // Check if `using static` directives meet constraints.
...@@ -586,7 +585,7 @@ private void Validate() ...@@ -586,7 +585,7 @@ private void Validate()
{ {
var typeSymbol = (TypeSymbol)@using.NamespaceOrType; var typeSymbol = (TypeSymbol)@using.NamespaceOrType;
var location = @using.UsingDirective?.Name.Location ?? NoLocation.Singleton; var location = @using.UsingDirective?.Name.Location ?? NoLocation.Singleton;
typeSymbol.CheckAllConstraints(_compilation, conversions, includeNullability, location, semanticDiagnostics); typeSymbol.CheckAllConstraints(_compilation, conversions, location, semanticDiagnostics);
} }
} }
......
...@@ -3189,7 +3189,7 @@ internal EffectiveParameters(ImmutableArray<TypeSymbolWithAnnotations> types, Im ...@@ -3189,7 +3189,7 @@ internal EffectiveParameters(ImmutableArray<TypeSymbolWithAnnotations> types, Im
var parameterTypes = leastOverriddenMember.GetParameterTypes(); var parameterTypes = leastOverriddenMember.GetParameterTypes();
for (int i = 0; i < parameterTypes.Length; i++) for (int i = 0; i < parameterTypes.Length; i++)
{ {
if (!parameterTypes[i].TypeSymbol.CheckAllConstraints(Compilation, Conversions, Conversions.IncludeNullability)) if (!parameterTypes[i].TypeSymbol.CheckAllConstraints(Compilation, Conversions))
{ {
return new MemberResolutionResult<TMember>(member, leastOverriddenMember, MemberAnalysisResult.ConstructedParameterFailedConstraintsCheck(i)); return new MemberResolutionResult<TMember>(member, leastOverriddenMember, MemberAnalysisResult.ConstructedParameterFailedConstraintsCheck(i));
} }
......
...@@ -974,7 +974,7 @@ private void ReportDuplicateNamedArgument(MemberResolutionResult<TMember> result ...@@ -974,7 +974,7 @@ private void ReportDuplicateNamedArgument(MemberResolutionResult<TMember> result
// formal parameter type. // formal parameter type.
TypeSymbol formalParameterType = method.ParameterTypes[result.Result.BadParameter].TypeSymbol; TypeSymbol formalParameterType = method.ParameterTypes[result.Result.BadParameter].TypeSymbol;
formalParameterType.CheckAllConstraints((CSharpCompilation)compilation, conversions.IncludeNullability, conversions, location, diagnostics); formalParameterType.CheckAllConstraints((CSharpCompilation)compilation, conversions, conversions.IncludeNullability, location, diagnostics);
return true; return true;
} }
......
...@@ -304,8 +304,7 @@ internal void CheckConstraints(DiagnosticBag diagnostics) ...@@ -304,8 +304,7 @@ internal void CheckConstraints(DiagnosticBag diagnostics)
{ {
var corLibrary = this.ContainingAssembly.CorLibrary; var corLibrary = this.ContainingAssembly.CorLibrary;
var conversions = new TypeConversions(corLibrary); var conversions = new TypeConversions(corLibrary);
bool includeNullability = DeclaringCompilation.IsFeatureEnabled(MessageID.IDS_FeatureNullableReferenceTypes); target.CheckAllConstraints(DeclaringCompilation, conversions, _locations[0], diagnostics);
target.CheckAllConstraints(DeclaringCompilation, conversions, includeNullability, _locations[0], diagnostics);
} }
} }
......
...@@ -459,26 +459,39 @@ internal static class ConstraintsHelper ...@@ -459,26 +459,39 @@ internal static class ConstraintsHelper
this TypeSymbol type, this TypeSymbol type,
CSharpCompilation compilation, CSharpCompilation compilation,
ConversionsBase conversions, ConversionsBase conversions,
bool includeNullability,
Location location, Location location,
DiagnosticBag diagnostics) DiagnosticBag diagnostics)
{ {
type.VisitType(s_checkConstraintsSingleTypeFunc, new CheckConstraintsArgs(compilation, conversions, includeNullability, location, diagnostics)); bool includeNullability = compilation.IsFeatureEnabled(MessageID.IDS_FeatureNullableReferenceTypes);
CheckAllConstraints(type, compilation, conversions, includeNullability, location, diagnostics);
} }
public static bool CheckAllConstraints( public static bool CheckAllConstraints(
this TypeSymbol type, this TypeSymbol type,
CSharpCompilation compilation, CSharpCompilation compilation,
ConversionsBase conversions, ConversionsBase conversions)
bool includeNullability)
{ {
var diagnostics = DiagnosticBag.GetInstance(); var diagnostics = DiagnosticBag.GetInstance();
type.CheckAllConstraints(compilation, conversions, includeNullability, NoLocation.Singleton, diagnostics);
// Nullability checks can only add warnings here so skip them for this check as we are only
// concerned with errors.
CheckAllConstraints(type, compilation, conversions, includeNullability: false, NoLocation.Singleton, diagnostics);
bool ok = !diagnostics.HasAnyErrors(); bool ok = !diagnostics.HasAnyErrors();
diagnostics.Free(); diagnostics.Free();
return ok; return ok;
} }
public static void CheckAllConstraints(
this TypeSymbol type,
CSharpCompilation compilation,
ConversionsBase conversions,
bool includeNullability,
Location location,
DiagnosticBag diagnostics)
{
type.VisitType(s_checkConstraintsSingleTypeFunc, new CheckConstraintsArgs(compilation, conversions, includeNullability, location, diagnostics));
}
private readonly struct CheckConstraintsArgs private readonly struct CheckConstraintsArgs
{ {
public readonly CSharpCompilation CurrentCompilation; public readonly CSharpCompilation CurrentCompilation;
......
...@@ -183,7 +183,7 @@ internal override void AfterAddingTypeMembersChecks(ConversionsBase conversions, ...@@ -183,7 +183,7 @@ internal override void AfterAddingTypeMembersChecks(ConversionsBase conversions,
{ {
var explicitInterfaceSpecifier = this.ExplicitInterfaceSpecifier; var explicitInterfaceSpecifier = this.ExplicitInterfaceSpecifier;
Debug.Assert(explicitInterfaceSpecifier != null); Debug.Assert(explicitInterfaceSpecifier != null);
_explicitInterfaceType.CheckAllConstraints(DeclaringCompilation, conversions, includeNullability, new SourceLocation(explicitInterfaceSpecifier.Name), diagnostics); _explicitInterfaceType.CheckAllConstraints(DeclaringCompilation, conversions, new SourceLocation(explicitInterfaceSpecifier.Name), diagnostics);
} }
if (!_explicitInterfaceImplementations.IsEmpty) if (!_explicitInterfaceImplementations.IsEmpty)
......
...@@ -671,7 +671,7 @@ internal override void AfterAddingTypeMembersChecks(ConversionsBase conversions, ...@@ -671,7 +671,7 @@ internal override void AfterAddingTypeMembersChecks(ConversionsBase conversions,
bool includeNullability = DeclaringCompilation.IsFeatureEnabled(MessageID.IDS_FeatureNullableReferenceTypes); bool includeNullability = DeclaringCompilation.IsFeatureEnabled(MessageID.IDS_FeatureNullableReferenceTypes);
this.CheckModifiersAndType(diagnostics); this.CheckModifiersAndType(diagnostics);
this.Type.CheckAllConstraints(DeclaringCompilation, conversions, includeNullablity, location, diagnostics); this.Type.CheckAllConstraints(DeclaringCompilation, conversions, location, diagnostics);
if (this.Type.NeedsNullableAttribute()) if (this.Type.NeedsNullableAttribute())
{ {
......
...@@ -575,8 +575,7 @@ internal override bool IsDefinedInSourceTree(SyntaxTree tree, TextSpan? definedW ...@@ -575,8 +575,7 @@ internal override bool IsDefinedInSourceTree(SyntaxTree tree, TextSpan? definedW
internal override void AfterAddingTypeMembersChecks(ConversionsBase conversions, DiagnosticBag diagnostics) internal override void AfterAddingTypeMembersChecks(ConversionsBase conversions, DiagnosticBag diagnostics)
{ {
var options = (CSharpParseOptions)SyntaxTree.Options; var options = (CSharpParseOptions)SyntaxTree.Options;
bool includeNullability = options.IsFeatureEnabled(MessageID.IDS_FeatureNullableReferenceTypes); Type.CheckAllConstraints(DeclaringCompilation, conversions, ErrorLocation, diagnostics);
Type.CheckAllConstraints(DeclaringCompilation, conversions, includeNullability, ErrorLocation, diagnostics);
base.AfterAddingTypeMembersChecks(conversions, diagnostics); base.AfterAddingTypeMembersChecks(conversions, diagnostics);
} }
} }
......
...@@ -106,8 +106,7 @@ protected override void CheckBase(DiagnosticBag diagnostics) ...@@ -106,8 +106,7 @@ protected override void CheckBase(DiagnosticBag diagnostics)
var corLibrary = this.ContainingAssembly.CorLibrary; var corLibrary = this.ContainingAssembly.CorLibrary;
var conversions = new TypeConversions(corLibrary); var conversions = new TypeConversions(corLibrary);
var location = singleDeclaration.NameLocation; var location = singleDeclaration.NameLocation;
bool includeNullability = DeclaringCompilation.IsFeatureEnabled(MessageID.IDS_FeatureNullableReferenceTypes); localBase.CheckAllConstraints(DeclaringCompilation, conversions, location, diagnostics);
localBase.CheckAllConstraints(DeclaringCompilation, conversions, includeNullability, location, diagnostics);
} }
} }
...@@ -132,7 +131,6 @@ protected override void CheckInterfaces(DiagnosticBag diagnostics) ...@@ -132,7 +131,6 @@ protected override void CheckInterfaces(DiagnosticBag diagnostics)
var corLibrary = this.ContainingAssembly.CorLibrary; var corLibrary = this.ContainingAssembly.CorLibrary;
var conversions = new TypeConversions(corLibrary); var conversions = new TypeConversions(corLibrary);
var location = singleDeclaration.NameLocation; var location = singleDeclaration.NameLocation;
bool includeNullability = DeclaringCompilation.IsFeatureEnabled(MessageID.IDS_FeatureNullableReferenceTypes);
foreach (var pair in interfaces) foreach (var pair in interfaces)
{ {
...@@ -140,11 +138,7 @@ protected override void CheckInterfaces(DiagnosticBag diagnostics) ...@@ -140,11 +138,7 @@ protected override void CheckInterfaces(DiagnosticBag diagnostics)
foreach (var @interface in set) foreach (var @interface in set)
{ {
<<<<<<< HEAD
@interface.CheckAllConstraints(DeclaringCompilation, conversions, location, diagnostics); @interface.CheckAllConstraints(DeclaringCompilation, conversions, location, diagnostics);
=======
@interface.CheckAllConstraints(conversions, includeNullability, location, diagnostics);
>>>>>>> Make nullability explicit constraint parameter
} }
if (set.Count > 1) if (set.Count > 1)
......
...@@ -1010,7 +1010,6 @@ internal override void ForceComplete(SourceLocation locationOpt, CancellationTok ...@@ -1010,7 +1010,6 @@ internal override void ForceComplete(SourceLocation locationOpt, CancellationTok
internal override void AfterAddingTypeMembersChecks(ConversionsBase conversions, DiagnosticBag diagnostics) internal override void AfterAddingTypeMembersChecks(ConversionsBase conversions, DiagnosticBag diagnostics)
{ {
var location = GetSyntax().ReturnType.Location; var location = GetSyntax().ReturnType.Location;
bool includeNullability = DeclaringCompilation.IsFeatureEnabled(MessageID.IDS_FeatureNullableReferenceTypes);
Debug.Assert(location != null); Debug.Assert(location != null);
...@@ -1022,14 +1021,14 @@ internal override void AfterAddingTypeMembersChecks(ConversionsBase conversions, ...@@ -1022,14 +1021,14 @@ internal override void AfterAddingTypeMembersChecks(ConversionsBase conversions,
{ {
var syntax = this.GetSyntax(); var syntax = this.GetSyntax();
Debug.Assert(syntax.ExplicitInterfaceSpecifier != null); Debug.Assert(syntax.ExplicitInterfaceSpecifier != null);
_explicitInterfaceType.CheckAllConstraints(DeclaringCompilation, conversions, includeNullability, new SourceLocation(syntax.ExplicitInterfaceSpecifier.Name), diagnostics); _explicitInterfaceType.CheckAllConstraints(DeclaringCompilation, conversions, new SourceLocation(syntax.ExplicitInterfaceSpecifier.Name), diagnostics);
} }
this.ReturnType.CheckAllConstraints(DeclaringCompilation, conversions, includeNullability, this.Locations[0], diagnostics); this.ReturnType.CheckAllConstraints(DeclaringCompilation, conversions, this.Locations[0], diagnostics);
foreach (var parameter in this.Parameters) foreach (var parameter in this.Parameters)
{ {
parameter.Type.CheckAllConstraints(DeclaringCompilation, conversions, includeNullability, parameter.Locations[0], diagnostics); parameter.Type.CheckAllConstraints(DeclaringCompilation, conversions, parameter.Locations[0], diagnostics);
} }
var implementingPart = this.SourcePartialImplementation; var implementingPart = this.SourcePartialImplementation;
......
...@@ -742,9 +742,8 @@ internal override void AfterAddingTypeMembersChecks(ConversionsBase conversions, ...@@ -742,9 +742,8 @@ internal override void AfterAddingTypeMembersChecks(ConversionsBase conversions,
if ((object)_explicitInterfaceType != null) if ((object)_explicitInterfaceType != null)
{ {
var explicitInterfaceSpecifier = GetExplicitInterfaceSpecifier(this.CSharpSyntaxNode); var explicitInterfaceSpecifier = GetExplicitInterfaceSpecifier(this.CSharpSyntaxNode);
bool includeNullability = DeclaringCompilation.IsFeatureEnabled(MessageID.IDS_FeatureNullableReferenceTypes);
Debug.Assert(explicitInterfaceSpecifier != null); Debug.Assert(explicitInterfaceSpecifier != null);
_explicitInterfaceType.CheckAllConstraints(DeclaringCompilation, conversions, includeNullability, new SourceLocation(explicitInterfaceSpecifier.Name), diagnostics); _explicitInterfaceType.CheckAllConstraints(DeclaringCompilation, conversions, new SourceLocation(explicitInterfaceSpecifier.Name), diagnostics);
// Note: we delayed nullable-related checks that could pull on NonNullTypes // Note: we delayed nullable-related checks that could pull on NonNullTypes
PropertySymbol overriddenOrImplementedProperty = null; PropertySymbol overriddenOrImplementedProperty = null;
...@@ -1380,11 +1379,10 @@ internal override void ForceComplete(SourceLocation locationOpt, CancellationTok ...@@ -1380,11 +1379,10 @@ internal override void ForceComplete(SourceLocation locationOpt, CancellationTok
{ {
var diagnostics = DiagnosticBag.GetInstance(); var diagnostics = DiagnosticBag.GetInstance();
var conversions = new TypeConversions(this.ContainingAssembly.CorLibrary); var conversions = new TypeConversions(this.ContainingAssembly.CorLibrary);
bool includeNullability = DeclaringCompilation.IsFeatureEnabled(MessageID.IDS_FeatureNullableReferenceTypes);
foreach (var parameter in this.Parameters) foreach (var parameter in this.Parameters)
{ {
parameter.ForceComplete(locationOpt, cancellationToken); parameter.ForceComplete(locationOpt, cancellationToken);
parameter.Type.CheckAllConstraints(DeclaringCompilation, conversions, includeNullability, parameter.Locations[0], diagnostics); parameter.Type.CheckAllConstraints(DeclaringCompilation, conversions, parameter.Locations[0], diagnostics);
} }
this.AddDeclarationDiagnostics(diagnostics); this.AddDeclarationDiagnostics(diagnostics);
...@@ -1411,7 +1409,7 @@ internal override void ForceComplete(SourceLocation locationOpt, CancellationTok ...@@ -1411,7 +1409,7 @@ internal override void ForceComplete(SourceLocation locationOpt, CancellationTok
var diagnostics = DiagnosticBag.GetInstance(); var diagnostics = DiagnosticBag.GetInstance();
var conversions = new TypeConversions(this.ContainingAssembly.CorLibrary); var conversions = new TypeConversions(this.ContainingAssembly.CorLibrary);
bool includeNullability = DeclaringCompilation.IsFeatureEnabled(MessageID.IDS_FeatureNullableReferenceTypes); bool includeNullability = DeclaringCompilation.IsFeatureEnabled(MessageID.IDS_FeatureNullableReferenceTypes);
this.Type.CheckAllConstraints(DeclaringCompilation, conversions, includeNullability, _location, diagnostics); this.Type.CheckAllConstraints(DeclaringCompilation, conversions, _location, diagnostics);
var type = this.Type.TypeSymbol; var type = this.Type.TypeSymbol;
if (type.IsRestrictedType(ignoreSpanLikeTypes: true)) if (type.IsRestrictedType(ignoreSpanLikeTypes: true))
......
...@@ -261,7 +261,6 @@ private void CheckConstraintTypeConstraints(DiagnosticBag diagnostics) ...@@ -261,7 +261,6 @@ private void CheckConstraintTypeConstraints(DiagnosticBag diagnostics)
var corLibrary = this.ContainingAssembly.CorLibrary; var corLibrary = this.ContainingAssembly.CorLibrary;
var conversions = new TypeConversions(corLibrary); var conversions = new TypeConversions(corLibrary);
bool includeNullability = DeclaringCompilation.IsFeatureEnabled(MessageID.IDS_FeatureNullableReferenceTypes);
var location = _locations[0]; var location = _locations[0];
foreach (var constraintType in constraintTypes) foreach (var constraintType in constraintTypes)
...@@ -271,7 +270,7 @@ private void CheckConstraintTypeConstraints(DiagnosticBag diagnostics) ...@@ -271,7 +270,7 @@ private void CheckConstraintTypeConstraints(DiagnosticBag diagnostics)
if (!diagnostics.Add(location, useSiteDiagnostics)) if (!diagnostics.Add(location, useSiteDiagnostics))
{ {
constraintType.CheckAllConstraints(DeclaringCompilation, conversions, includeNullability, location, diagnostics); constraintType.CheckAllConstraints(DeclaringCompilation, conversions, location, diagnostics);
} }
} }
} }
......
...@@ -644,12 +644,11 @@ internal sealed override void AfterAddingTypeMembersChecks(ConversionsBase conve ...@@ -644,12 +644,11 @@ internal sealed override void AfterAddingTypeMembersChecks(ConversionsBase conve
// method name location for any such errors. We'll do the same for return // method name location for any such errors. We'll do the same for return
// type errors but for parameter errors, we'll use the parameter location. // type errors but for parameter errors, we'll use the parameter location.
bool includeNullability = DeclaringCompilation.IsFeatureEnabled(MessageID.IDS_FeatureNullableReferenceTypes); this.ReturnType.CheckAllConstraints(DeclaringCompilation, conversions, this.Locations[0], diagnostics);
this.ReturnType.CheckAllConstraints(DeclaringCompilation, conversions, includeNullability, this.Locations[0], diagnostics);
foreach (var parameter in this.Parameters) foreach (var parameter in this.Parameters)
{ {
parameter.Type.CheckAllConstraints(DeclaringCompilation, conversions, includeNullability, parameter.Locations[0], diagnostics); parameter.Type.CheckAllConstraints(DeclaringCompilation, conversions, parameter.Locations[0], diagnostics);
} }
ParameterHelpers.EnsureIsReadOnlyAttributeExists(Parameters, diagnostics, modifyCompilation: true); ParameterHelpers.EnsureIsReadOnlyAttributeExists(Parameters, diagnostics, modifyCompilation: true);
......
...@@ -584,7 +584,7 @@ internal bool GetIsValueType(ConsList<TypeParameterSymbol> inProgress) ...@@ -584,7 +584,7 @@ internal bool GetIsValueType(ConsList<TypeParameterSymbol> inProgress)
} }
public sealed override bool IsValueType => GetIsValueType(ConsList<TypeParameterSymbol>.Empty); public sealed override bool IsValueType => GetIsValueType(ConsList<TypeParameterSymbol>.Empty);
internal sealed override ManagedKind ManagedKind internal sealed override ManagedKind ManagedKind
{ {
get get
......
...@@ -730,9 +730,9 @@ public bool GetUnificationUseSiteDiagnosticRecursive(ref DiagnosticInfo result, ...@@ -730,9 +730,9 @@ public bool GetUnificationUseSiteDiagnosticRecursive(ref DiagnosticInfo result,
Symbol.GetUnificationUseSiteDiagnosticRecursive(ref result, this.CustomModifiers, owner, ref checkedTypes); Symbol.GetUnificationUseSiteDiagnosticRecursive(ref result, this.CustomModifiers, owner, ref checkedTypes);
} }
public void CheckAllConstraints(CSharpCompilation compilation, ConversionsBase conversions, bool includeNullability, Location location, DiagnosticBag diagnostics) public void CheckAllConstraints(CSharpCompilation compilation, ConversionsBase conversions, Location location, DiagnosticBag diagnostics)
{ {
TypeSymbol.CheckAllConstraints(compilation, conversions, includeNullability, location, diagnostics); TypeSymbol.CheckAllConstraints(compilation, conversions, location, diagnostics);
} }
public bool IsAtLeastAsVisibleAs(Symbol sym, ref HashSet<DiagnosticInfo> useSiteDiagnostics) public bool IsAtLeastAsVisibleAs(Symbol sym, ref HashSet<DiagnosticInfo> useSiteDiagnostics)
......
...@@ -57031,10 +57031,7 @@ class B4 : A<string?> ...@@ -57031,10 +57031,7 @@ class B4 : A<string?>
comp.VerifyDiagnostics( comp.VerifyDiagnostics(
// (11,20): warning CS8632: The annotation for nullable reference types should only be used in code within a '#nullable' context. // (11,20): warning CS8632: The annotation for nullable reference types should only be used in code within a '#nullable' context.
// class B2 : A<string?> // class B2 : A<string?>
Diagnostic(ErrorCode.WRN_MissingNonNullTypesContextForAnnotation, "?").WithLocation(11, 20), Diagnostic(ErrorCode.WRN_MissingNonNullTypesContextForAnnotation, "?").WithLocation(11, 20)
// (27,7): warning CS8634: The type 'string?' cannot be used as type parameter 'T' in the generic type or method 'A<T>'. Nullability of type argument 'string?' doesn't match 'class' constraint.
// class B4 : A<string?>
Diagnostic(ErrorCode.WRN_NullabilityMismatchInTypeParameterReferenceTypeConstraint, "B4").WithArguments("A<T>", "T", "string?").WithLocation(27, 7)
); );
verifyAllConstraintTypes(); verifyAllConstraintTypes();
...@@ -57063,7 +57060,10 @@ class B4 : A<string?> ...@@ -57063,7 +57060,10 @@ class B4 : A<string?>
comp.VerifyDiagnostics( comp.VerifyDiagnostics(
// (11,20): warning CS8632: The annotation for nullable reference types should only be used in code within a '#nullable' context. // (11,20): warning CS8632: The annotation for nullable reference types should only be used in code within a '#nullable' context.
// class B2 : A<string?> // class B2 : A<string?>
Diagnostic(ErrorCode.WRN_MissingNonNullTypesContextForAnnotation, "?").WithLocation(11, 20) Diagnostic(ErrorCode.WRN_MissingNonNullTypesContextForAnnotation, "?").WithLocation(11, 20),
// (27,7): warning CS8634: The type 'string?' cannot be used as type parameter 'T' in the generic type or method 'A<T>'. Nullability of type argument 'string?' doesn't match 'class' constraint.
// class B4 : A<string?>
Diagnostic(ErrorCode.WRN_NullabilityMismatchInTypeParameterReferenceTypeConstraint, "B4").WithArguments("A<T>", "T", "string?").WithLocation(27, 7)
); );
verifyAllConstraintTypes(); verifyAllConstraintTypes();
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册