本文整理汇总了C#中TypeSymbol.GetNullableUnderlyingType方法的典型用法代码示例。如果您正苦于以下问题:C# TypeSymbol.GetNullableUnderlyingType方法的具体用法?C# TypeSymbol.GetNullableUnderlyingType怎么用?C# TypeSymbol.GetNullableUnderlyingType使用的例子?那么恭喜您, 这里精选的方法代码示例或许可以为您提供帮助。您也可以进一步了解该方法所在类TypeSymbol
的用法示例。
在下文中一共展示了TypeSymbol.GetNullableUnderlyingType方法的15个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于系统推荐出更棒的C#代码示例。
示例1: ConvertPatternExpression
internal BoundExpression ConvertPatternExpression(TypeSymbol inputType, CSharpSyntaxNode node, BoundExpression expression, ref ConstantValue constantValue, DiagnosticBag diagnostics)
{
// NOTE: This will allow user-defined conversions, even though they're not allowed here. This is acceptable
// because the result of a user-defined conversion does not have a ConstantValue and we'll report a diagnostic
// to that effect later.
BoundExpression convertedExpression = GenerateConversionForAssignment(inputType, expression, diagnostics);
if (convertedExpression.Kind == BoundKind.Conversion)
{
var conversion = (BoundConversion)convertedExpression;
var operand = conversion.Operand;
if (inputType.IsNullableType() && (convertedExpression.ConstantValue == null || !convertedExpression.ConstantValue.IsNull))
{
// Null is a special case here because we want to compare null to the Nullable<T> itself, not to the underlying type.
var discardedDiagnostics = DiagnosticBag.GetInstance(); // We are not intested in the diagnostic that get created here
convertedExpression = CreateConversion(operand, inputType.GetNullableUnderlyingType(), discardedDiagnostics);
discardedDiagnostics.Free();
}
else if ((conversion.ConversionKind == ConversionKind.Boxing || conversion.ConversionKind == ConversionKind.ImplicitReference)
&& operand.ConstantValue != null && convertedExpression.ConstantValue == null)
{
// A boxed constant (or string converted to object) is a special case because we prefer
// to compare to the pre-converted value by casting the input value to the type of the constant
// (that is, unboxing or downcasting it) and then testing the resulting value using primitives.
// That is much more efficient than calling object.Equals(x, y), and we can share the downcasted
// input value among many constant tests.
convertedExpression = operand;
}
}
constantValue = convertedExpression.ConstantValue;
return convertedExpression;
}
示例2: GetLiftedUnaryOperatorConsequence
private BoundExpression GetLiftedUnaryOperatorConsequence(UnaryOperatorKind kind, CSharpSyntaxNode syntax, MethodSymbol method, TypeSymbol type, BoundExpression nonNullOperand)
{
MethodSymbol ctor = GetNullableMethod(syntax, type, SpecialMember.System_Nullable_T__ctor);
// OP(temp.GetValueOrDefault())
BoundExpression unliftedOp = MakeUnaryOperator(
oldNode: null,
kind: kind.Unlifted(),
syntax: syntax,
method: method,
loweredOperand: nonNullOperand,
type: type.GetNullableUnderlyingType());
// new R?(OP(temp.GetValueOrDefault()))
BoundExpression consequence = new BoundObjectCreationExpression(
syntax,
ctor,
unliftedOp);
return consequence;
}
示例3: ConvertCaseExpression
private BoundExpression ConvertCaseExpression(TypeSymbol switchGoverningType, CSharpSyntaxNode node, BoundExpression caseExpression, Binder sectionBinder, ref ConstantValue constantValueOpt, DiagnosticBag diagnostics, bool isGotoCaseExpr = false)
{
BoundExpression convertedCaseExpression;
if (!isGotoCaseExpr)
{
// NOTE: This will allow user-defined conversions, even though they're not allowed here. This is acceptable
// because the result of a user-defined conversion does not have a ConstantValue and we'll report a diagnostic
// to that effect below (same error code as Dev10).
convertedCaseExpression = sectionBinder.GenerateConversionForAssignment(switchGoverningType, caseExpression, diagnostics);
}
else
{
// SPEC VIOLATION for Dev10 COMPATIBILITY:
// Dev10 compiler violates the SPEC comment below:
// "if the constant-expression is not implicitly convertible (§6.1) to
// the governing type of the nearest enclosing switch statement,
// a compile-time error occurs"
// If there is no implicit conversion from gotoCaseExpression to switchGoverningType,
// but there exists an explicit conversion, Dev10 compiler generates a warning "WRN_GotoCaseShouldConvert"
// instead of an error. See test "CS0469_NoImplicitConversionWarning".
// CONSIDER: Should we introduce a breaking change and violate Dev10 compatibility and follow the spec?
HashSet<DiagnosticInfo> useSiteDiagnostics = null;
Conversion conversion = sectionBinder.Conversions.ClassifyConversionFromExpression(caseExpression, switchGoverningType, ref useSiteDiagnostics);
diagnostics.Add(node, useSiteDiagnostics);
if (!conversion.IsValid)
{
GenerateImplicitConversionError(diagnostics, node, conversion, caseExpression, switchGoverningType);
}
else if (!conversion.IsImplicit)
{
diagnostics.Add(ErrorCode.WRN_GotoCaseShouldConvert, node.Location, switchGoverningType);
}
convertedCaseExpression = sectionBinder.CreateConversion(caseExpression, conversion, switchGoverningType, diagnostics);
}
if (switchGoverningType.IsNullableType()
&& convertedCaseExpression.Kind == BoundKind.Conversion
// Null is a special case here because we want to compare null to the Nullable<T> itself, not to the underlying type.
&& (convertedCaseExpression.ConstantValue == null || !convertedCaseExpression.ConstantValue.IsNull))
{
var operand = ((BoundConversion)convertedCaseExpression).Operand;
// We are not intested in the diagnostic that get created here
var diagnosticBag = DiagnosticBag.GetInstance();
constantValueOpt = sectionBinder.CreateConversion(operand, switchGoverningType.GetNullableUnderlyingType(), diagnosticBag).ConstantValue;
diagnosticBag.Free();
}
else
{
constantValueOpt = convertedCaseExpression.ConstantValue;
}
return convertedCaseExpression;
}
示例4: TypeToIndex
private static int? TypeToIndex(TypeSymbol type)
{
switch (type.GetSpecialTypeSafe())
{
case SpecialType.System_Object: return 0;
case SpecialType.System_String: return 1;
case SpecialType.System_Boolean: return 2;
case SpecialType.System_Char: return 3;
case SpecialType.System_SByte: return 4;
case SpecialType.System_Int16: return 5;
case SpecialType.System_Int32: return 6;
case SpecialType.System_Int64: return 7;
case SpecialType.System_Byte: return 8;
case SpecialType.System_UInt16: return 9;
case SpecialType.System_UInt32: return 10;
case SpecialType.System_UInt64: return 11;
case SpecialType.System_Single: return 12;
case SpecialType.System_Double: return 13;
case SpecialType.System_Decimal: return 14;
case SpecialType.None:
if (type != null && type.IsNullableType())
{
TypeSymbol underlyingType = type.GetNullableUnderlyingType();
switch (underlyingType.GetSpecialTypeSafe())
{
case SpecialType.System_Boolean: return 15;
case SpecialType.System_Char: return 16;
case SpecialType.System_SByte: return 17;
case SpecialType.System_Int16: return 18;
case SpecialType.System_Int32: return 19;
case SpecialType.System_Int64: return 20;
case SpecialType.System_Byte: return 21;
case SpecialType.System_UInt16: return 22;
case SpecialType.System_UInt32: return 23;
case SpecialType.System_UInt64: return 24;
case SpecialType.System_Single: return 25;
case SpecialType.System_Double: return 26;
case SpecialType.System_Decimal: return 27;
}
}
// fall through
goto default;
default: return null;
}
}
示例5: TypeOrUnderlyingType
private TypeSymbol TypeOrUnderlyingType(TypeSymbol type)
{
if (type.IsNullableType())
{
return type.GetNullableUnderlyingType();
}
return type;
}
示例6: HasImplicitEnumerationConversion
private static bool HasImplicitEnumerationConversion(BoundExpression source, TypeSymbol destination)
{
Debug.Assert((object)source != null);
Debug.Assert((object)destination != null);
// SPEC: An implicit enumeration conversion permits the decimal-integer-literal 0 to be converted to any enum-type
// SPEC: and to any nullable-type whose underlying type is an enum-type.
//
// For historical reasons we actually allow a conversion from any *numeric constant
// zero* to be converted to any enum type, not just the literal integer zero.
bool validType = destination.IsEnumType() ||
destination.IsNullableType() && destination.GetNullableUnderlyingType().IsEnumType();
if (!validType)
{
return false;
}
var sourceConstantValue = source.ConstantValue;
return sourceConstantValue != null &&
IsNumericType(source.Type.GetSpecialTypeSafe()) &&
IsConstantNumericZero(sourceConstantValue);
}
示例7: AddUserDefinedConversionsToExplicitCandidateSet
private void AddUserDefinedConversionsToExplicitCandidateSet(
BoundExpression sourceExpression,
TypeSymbol source,
TypeSymbol target,
ArrayBuilder<UserDefinedConversionAnalysis> u,
NamedTypeSymbol declaringType,
string operatorName,
ref HashSet<DiagnosticInfo> useSiteDiagnostics)
{
Debug.Assert(sourceExpression != null || (object)source != null);
Debug.Assert((object)target != null);
Debug.Assert(u != null);
Debug.Assert((object)declaringType != null);
Debug.Assert(operatorName != null);
// SPEC: Find the set of applicable user-defined and lifted conversion operators, U.
// SPEC: The set consists of the user-defined and lifted implicit or explicit
// SPEC: conversion operators declared by the classes and structs in D that convert
// SPEC: from a type encompassing E or encompassed by S (if it exists) to a type
// SPEC: encompassing or encompassed by T.
// DELIBERATE SPEC VIOLATION:
//
// The spec here essentially says that we add an applicable "regular" conversion and
// an applicable lifted conversion, if there is one, to the candidate set, and then
// let them duke it out to determine which one is "best".
//
// This is not at all what the native compiler does, and attempting to implement
// the specification, or slight variations on it, produces too many backwards-compatibility
// breaking changes.
//
// The native compiler deviates from the specification in two major ways here.
// First, it does not add *both* the regular and lifted forms to the candidate set.
// Second, the way it characterizes a "lifted" form is very, very different from
// how the specification characterizes a lifted form.
//
// An operation, in this case, X-->Y, is properly said to be "lifted" to X?-->Y? via
// the rule that X?-->Y? matches the behavior of X-->Y for non-null X, and converts
// null X to null Y otherwise.
//
// The native compiler, by contrast, takes the existing operator and "lifts" either
// the operator's parameter type or the operator's return type to nullable. For
// example, a conversion from X?-->Y would be "lifted" to X?-->Y? by making the
// conversion from X? to Y, and then from Y to Y?. No "lifting" semantics
// are imposed; we do not check to see if the X? is null. This operator is not
// actually "lifted" at all; rather, an implicit conversion is applied to the
// output. **The native compiler considers the result type Y? of that standard implicit
// conversion to be the result type of the "lifted" conversion**, rather than
// properly considering Y to be the result type of the conversion for the purposes
// of computing the best output type.
//
// Moreover: the native compiler actually *does* implement nullable lifting semantics
// in the case where the input type of the user-defined conversion is a non-nullable
// value type and the output type is a nullable value type **or pointer type, or
// reference type**. This is an enormous departure from the specification; the
// native compiler will take a user-defined conversion from X-->Y? or X-->C and "lift"
// it to a conversion from X?-->Y? or X?-->C that has nullable semantics.
//
// This is quite confusing. In this code we will classify the conversion as either
// "normal" or "lifted" on the basis of *whether or not special lifting semantics
// are to be applied*. That is, whether or not a later rewriting pass is going to
// need to insert a check to see if the source expression is null, and decide
// whether or not to call the underlying unlifted conversion or produce a null
// value without calling the unlifted conversion.
// DELIBERATE SPEC VIOLATION: See the comment regarding bug 17021 in
// UserDefinedImplicitConversions.cs.
if ((object)source != null && source.IsInterfaceType() || target.IsInterfaceType())
{
return;
}
foreach (MethodSymbol op in declaringType.GetOperators(operatorName))
{
// We might have a bad operator and be in an error recovery situation. Ignore it.
if (op.ReturnsVoid || op.ParameterCount != 1 || op.ReturnType.TypeKind == TypeKind.Error)
{
continue;
}
TypeSymbol convertsFrom = op.ParameterTypes[0];
TypeSymbol convertsTo = op.ReturnType;
Conversion fromConversion = EncompassingExplicitConversion(sourceExpression, source, convertsFrom, ref useSiteDiagnostics);
Conversion toConversion = EncompassingExplicitConversion(null, convertsTo, target, ref useSiteDiagnostics);
// We accept candidates for which the parameter type encompasses the *underlying* source type.
if (!fromConversion.Exists &&
(object)source != null &&
source.IsNullableType() &&
EncompassingExplicitConversion(null, source.GetNullableUnderlyingType(), convertsFrom, ref useSiteDiagnostics).Exists)
{
fromConversion = ClassifyConversion(source, convertsFrom, ref useSiteDiagnostics, builtinOnly: true);
}
// As in dev11 (and the revised spec), we also accept candidates for which the return type is encompassed by the *stripped* target type.
if (!toConversion.Exists &&
(object)target != null &&
target.IsNullableType() &&
EncompassingExplicitConversion(null, convertsTo, target.GetNullableUnderlyingType(), ref useSiteDiagnostics).Exists)
{
//.........这里部分代码省略.........
示例8: RewriteFullyLiftedBuiltInConversion
private BoundExpression RewriteFullyLiftedBuiltInConversion(
CSharpSyntaxNode syntax,
BoundExpression operand,
ConversionKind kind,
bool @checked,
TypeSymbol type)
{
// SPEC: If the nullable conversion is from S? to T?:
// SPEC: * If the source HasValue property is false the result
// SPEC: is a null value of type T?.
// SPEC: * Otherwise the conversion is evaluated as an unwrapping
// SPEC: from S? to S, followed by the underlying conversion from
// SPEC: S to T, followed by a wrapping from T to T?
BoundExpression optimized = OptimizeLiftedBuiltInConversion(syntax, operand, kind, @checked, type);
if (optimized != null)
{
return optimized;
}
// We are unable to optimize the conversion. "(T?)s" is generated as:
// S? temp = s;
// temp.HasValue ? new T?((T)temp.GetValueOrDefault()) : default(T?)
BoundAssignmentOperator tempAssignment;
var boundTemp = factory.StoreToTemp(operand, out tempAssignment);
MethodSymbol get_HasValue = GetNullableMethod(syntax, boundTemp.Type, SpecialMember.System_Nullable_T_get_HasValue);
MethodSymbol getValueOrDefault = GetNullableMethod(syntax, boundTemp.Type, SpecialMember.System_Nullable_T_GetValueOrDefault);
BoundExpression condition = BoundCall.Synthesized(syntax, boundTemp, get_HasValue);
BoundExpression consequence = new BoundObjectCreationExpression(
syntax,
GetNullableMethod(syntax, type, SpecialMember.System_Nullable_T__ctor),
MakeConversion(
BoundCall.Synthesized(syntax, boundTemp, getValueOrDefault),
type.GetNullableUnderlyingType(),
@checked));
BoundExpression alternative = new BoundDefaultOperator(syntax, null, type);
BoundExpression conditionalExpression = RewriteConditionalOperator(
syntax: syntax,
rewrittenCondition: condition,
rewrittenConsequence: consequence,
rewrittenAlternative: alternative,
constantValueOpt: null,
rewrittenType: type);
return new BoundSequence(
syntax: syntax,
locals: ImmutableArray.Create(boundTemp.LocalSymbol),
sideEffects: ImmutableArray.Create<BoundExpression>(tempAssignment),
value: conditionalExpression,
type: type);
}
示例9: OptimizeLiftedBuiltInConversion
private BoundExpression OptimizeLiftedBuiltInConversion(
CSharpSyntaxNode syntax,
BoundExpression operand,
ConversionKind kind,
bool @checked,
TypeSymbol type)
{
Debug.Assert(operand != null);
Debug.Assert((object)type != null);
// First, an optimization. If the source is known to always be null then
// we can simply return the alternative.
if (NullableNeverHasValue(operand))
{
return new BoundDefaultOperator(syntax, null, type);
}
// Second, a trickier optimization. If the conversion is "(T?)(new S?(x))" then
// we generate "new T?((T)x)"
BoundExpression nonNullValue = NullableAlwaysHasValue(operand);
if (nonNullValue != null)
{
return new BoundObjectCreationExpression(
syntax,
GetNullableMethod(syntax, type, SpecialMember.System_Nullable_T__ctor),
MakeConversion(
nonNullValue,
type.GetNullableUnderlyingType(),
@checked));
}
// Third, a very tricky optimization.
return DistributeLiftedConversionIntoLiftedOperand(syntax, operand, kind, @checked, null, type);
}
示例10: LowerBoundNullableInference
private bool LowerBoundNullableInference(TypeSymbol source, TypeSymbol target, ref HashSet<DiagnosticInfo> useSiteDiagnostics)
{
Debug.Assert((object)source != null);
Debug.Assert((object)target != null);
if (!source.IsNullableType() || !target.IsNullableType())
{
return false;
}
LowerBoundInference(source.GetNullableUnderlyingType(), target.GetNullableUnderlyingType(), ref useSiteDiagnostics);
return true;
}
示例11: RewriteNullableConversion
private BoundExpression RewriteNullableConversion(
CSharpSyntaxNode syntax,
BoundExpression rewrittenOperand,
ConversionKind conversionKind,
bool @checked,
bool explicitCastInCode,
TypeSymbol rewrittenType)
{
Debug.Assert((object)rewrittenType != null);
if (inExpressionLambda)
{
return RewriteLiftedConversionInExpressionTree(syntax, rewrittenOperand, conversionKind, @checked, explicitCastInCode, rewrittenType);
}
TypeSymbol rewrittenOperandType = rewrittenOperand.Type;
Debug.Assert(rewrittenType.IsNullableType() || rewrittenOperandType.IsNullableType());
if (rewrittenOperandType.IsNullableType() && rewrittenType.IsNullableType())
{
return RewriteFullyLiftedBuiltInConversion(syntax, rewrittenOperand, conversionKind, @checked, rewrittenType);
}
else if (rewrittenType.IsNullableType())
{
// SPEC: If the nullable conversion is from S to T?, the conversion is
// SPEC: evaluated as the underlying conversion from S to T followed
// SPEC: by a wrapping from T to T?.
BoundExpression rewrittenConversion = MakeConversion(rewrittenOperand, rewrittenType.GetNullableUnderlyingType(), @checked);
MethodSymbol ctor = GetNullableMethod(syntax, rewrittenType, SpecialMember.System_Nullable_T__ctor);
return new BoundObjectCreationExpression(syntax, ctor, rewrittenConversion);
}
else
{
// SPEC: if the nullable conversion is from S? to T, the conversion is
// SPEC: evaluated as an unwrapping from S? to S followed by the underlying
// SPEC: conversion from S to T.
// We can do a simple optimization here if we know that the source is never null:
BoundExpression nonNullValue = NullableAlwaysHasValue(rewrittenOperand);
if (nonNullValue != null)
{
return MakeConversion(nonNullValue, rewrittenType, @checked);
}
// (If the source is known to be null then we need to keep the call to get Value
// in place so that it throws at runtime.)
MethodSymbol get_Value = GetNullableMethod(syntax, rewrittenOperandType, SpecialMember.System_Nullable_T_get_Value);
return MakeConversion(BoundCall.Synthesized(syntax, rewrittenOperand, get_Value), rewrittenType, @checked);
}
}
示例12: LowerBoundNullableInference
private bool LowerBoundNullableInference(TypeSymbol source, TypeSymbol target, ref HashSet<DiagnosticInfo> useSiteDiagnostics)
{
Debug.Assert((object)source != null);
Debug.Assert((object)target != null);
// SPEC ISSUE: As noted above, the spec does not clearly call out how
// SPEC ISSUE: to do type inference to a nullable target. I propose the
// SPEC ISSUE: following:
// SPEC ISSUE:
// SPEC ISSUE: * Otherwise, if V is nullable type V1? and U is a
// SPEC ISSUE: non-nullable struct type then an exact inference is made from U to V1.
if (!target.IsNullableType() || !source.IsValueType || source.IsNullableType())
{
return false;
}
ExactInference(source, target.GetNullableUnderlyingType(), ref useSiteDiagnostics);
return true;
}
示例13: CreateTupleLiteralConversion
private BoundExpression CreateTupleLiteralConversion(CSharpSyntaxNode syntax, BoundTupleLiteral sourceTuple, Conversion conversion, bool isCast, TypeSymbol destination, DiagnosticBag diagnostics)
{
// We have a successful tuple conversion; rather than producing a separate conversion node
// which is a conversion on top of a tuple literal, tuple conversion is an element-wise conversion of arguments.
Debug.Assert(conversion.Kind == ConversionKind.ImplicitTupleLiteral || conversion.Kind == ConversionKind.ImplicitNullable);
Debug.Assert((conversion.Kind == ConversionKind.ImplicitNullable) == destination.IsNullableType());
TypeSymbol destinationWithoutNullable = conversion.Kind == ConversionKind.ImplicitNullable ?
destinationWithoutNullable = destination.GetNullableUnderlyingType() :
destination;
NamedTypeSymbol targetType = (NamedTypeSymbol)destinationWithoutNullable;
if (targetType.IsTupleType)
{
var destTupleType = (TupleTypeSymbol)targetType;
// do not lose the original element names in the literal if different from names in the target
// Come back to this, what about locations? (https://github.com/dotnet/roslyn/issues/11013)
targetType = destTupleType.WithElementNames(sourceTuple.ArgumentNamesOpt);
}
var arguments = sourceTuple.Arguments;
var convertedArguments = ArrayBuilder<BoundExpression>.GetInstance(arguments.Length);
ImmutableArray<TypeSymbol> targetElementTypes = targetType.GetElementTypesOfTupleOrCompatible();
Debug.Assert(targetElementTypes.Length == arguments.Length, "converting a tuple literal to incompatible type?");
for (int i = 0; i < arguments.Length; i++)
{
var argument = arguments[i];
var destType = targetElementTypes[i];
HashSet<DiagnosticInfo> useSiteDiagnostics = null;
Conversion elementConversion;
if (isCast)
{
elementConversion = this.Conversions.ClassifyConversionForCast(argument, destType, ref useSiteDiagnostics);
}
else
{
elementConversion = this.Conversions.ClassifyConversionFromExpression(argument, destType, ref useSiteDiagnostics);
}
diagnostics.Add(syntax, useSiteDiagnostics);
convertedArguments.Add(CreateConversion(argument.Syntax, argument, elementConversion, isCast, destType, diagnostics));
}
BoundExpression result = new BoundConvertedTupleLiteral(
sourceTuple.Syntax,
sourceTuple.Type,
convertedArguments.ToImmutableAndFree(),
targetType);
// We need to preserve any conversion that changes the type (even identity conversions),
// or that was explicitly written in code (so that GetSemanticInfo can find the syntax in the bound tree).
if (!isCast && targetType == destination)
{
return result;
}
// if we have a nullable cast combined with a name/dynamic cast
// name/dynamic cast must happen before converting to nullable
if (conversion.Kind == ConversionKind.ImplicitNullable &&
destinationWithoutNullable != targetType)
{
Debug.Assert(destinationWithoutNullable.Equals(targetType, ignoreDynamic: true));
result = new BoundConversion(
syntax,
result,
Conversion.Identity,
@checked: false,
explicitCastInCode: isCast,
constantValueOpt: ConstantValue.NotAvailable,
type: destinationWithoutNullable)
{ WasCompilerGenerated = sourceTuple.WasCompilerGenerated };
}
return new BoundConversion(
syntax,
result,
conversion,
@checked: false,
explicitCastInCode: isCast,
constantValueOpt: ConstantValue.NotAvailable,
type: destination)
{ WasCompilerGenerated = sourceTuple.WasCompilerGenerated };
}
示例14: CreateTupleLiteralConversion
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
// which is a conversion on top of a tuple literal, tuple conversion is an element-wise conversion of arguments.
Debug.Assert((conversion.Kind == ConversionKind.ImplicitNullable) == destination.IsNullableType());
var destinationWithoutNullable = destination;
var conversionWithoutNullable = conversion;
if (conversion.Kind == ConversionKind.ImplicitNullable)
{
destinationWithoutNullable = destination.GetNullableUnderlyingType();
conversionWithoutNullable = conversion.UnderlyingConversions[0];
}
Debug.Assert(conversionWithoutNullable.IsTupleLiteralConversion);
NamedTypeSymbol targetType = (NamedTypeSymbol)destinationWithoutNullable;
if (targetType.IsTupleType)
{
var destTupleType = (TupleTypeSymbol)targetType;
// do not lose the original element names in the literal if different from names in the target
TupleTypeSymbol.ReportNamesMismatchesIfAny(targetType, sourceTuple, diagnostics);
// Come back to this, what about locations? (https://github.com/dotnet/roslyn/issues/11013)
targetType = destTupleType.WithElementNames(sourceTuple.ArgumentNamesOpt);
}
var arguments = sourceTuple.Arguments;
var convertedArguments = ArrayBuilder<BoundExpression>.GetInstance(arguments.Length);
ImmutableArray<TypeSymbol> targetElementTypes = targetType.GetElementTypesOfTupleOrCompatible();
Debug.Assert(targetElementTypes.Length == arguments.Length, "converting a tuple literal to incompatible type?");
var underlyingConversions = conversionWithoutNullable.UnderlyingConversions;
for (int i = 0; i < arguments.Length; i++)
{
var argument = arguments[i];
var destType = targetElementTypes[i];
var elementConversion = underlyingConversions[i];
convertedArguments.Add(CreateConversion(argument.Syntax, argument, elementConversion, isCast, destType, diagnostics));
}
BoundExpression result = new BoundConvertedTupleLiteral(
sourceTuple.Syntax,
sourceTuple.Type,
convertedArguments.ToImmutableAndFree(),
targetType);
if (sourceTuple.Type != destination)
{
// literal cast is applied to the literal
result = new BoundConversion(
sourceTuple.Syntax,
result,
conversion,
@checked: false,
explicitCastInCode: isCast,
constantValueOpt: ConstantValue.NotAvailable,
type: destination);
}
// If we had a cast in the code, keep conversion in the tree.
// even though the literal is already converted to the target type.
if (isCast)
{
result = new BoundConversion(
syntax,
result,
Conversion.Identity,
@checked: false,
explicitCastInCode: isCast,
constantValueOpt: ConstantValue.NotAvailable,
type: destination);
}
return result;
}
示例15: CheckValidPatternType
private bool CheckValidPatternType(
CSharpSyntaxNode typeSyntax,
BoundExpression operand,
TypeSymbol operandType,
TypeSymbol patternType,
bool patternTypeWasInSource,
bool isVar,
DiagnosticBag diagnostics)
{
if (operandType?.IsErrorType() == true || patternType?.IsErrorType() == true)
{
return false;
}
else if (patternType.IsNullableType() && !isVar && patternTypeWasInSource)
{
// It is an error to use pattern-matching with a nullable type, because you'll never get null. Use the underlying type.
Error(diagnostics, ErrorCode.ERR_PatternNullableType, typeSyntax, patternType, patternType.GetNullableUnderlyingType());
return true;
}
else if (patternType.IsStatic)
{
Error(diagnostics, ErrorCode.ERR_VarDeclIsStaticClass, typeSyntax, patternType);
return true;
}
else if (operand != null && operandType == (object)null && !operand.HasAnyErrors)
{
// It is an error to use pattern-matching with a null, method group, or lambda
Error(diagnostics, ErrorCode.ERR_BadIsPatternExpression, operand.Syntax);
return true;
}
else if (!isVar)
{
HashSet<DiagnosticInfo> useSiteDiagnostics = null;
Conversion conversion =
operand != null
? this.Conversions.ClassifyConversionFromExpression(operand, patternType, ref useSiteDiagnostics, forCast: true)
: this.Conversions.ClassifyConversionFromType(operandType, patternType, ref useSiteDiagnostics, forCast: true);
diagnostics.Add(typeSyntax, useSiteDiagnostics);
switch (conversion.Kind)
{
case ConversionKind.Boxing:
case ConversionKind.ExplicitNullable:
case ConversionKind.ExplicitReference:
case ConversionKind.Identity:
case ConversionKind.ImplicitReference:
case ConversionKind.Unboxing:
case ConversionKind.NullLiteral:
case ConversionKind.ImplicitNullable:
// these are the conversions allowed by a pattern match
break;
//case ConversionKind.ExplicitNumeric: // we do not perform numeric conversions of the operand
//case ConversionKind.ImplicitConstant:
//case ConversionKind.ImplicitNumeric:
default:
Error(diagnostics, ErrorCode.ERR_PatternWrongType, typeSyntax, operandType, patternType);
return true;
}
}
return false;
}