本文整理汇总了C#中TypeSymbol.IsNullableType方法的典型用法代码示例。如果您正苦于以下问题:C# TypeSymbol.IsNullableType方法的具体用法?C# TypeSymbol.IsNullableType怎么用?C# TypeSymbol.IsNullableType使用的例子?那么恭喜您, 这里精选的方法代码示例或许可以为您提供帮助。您也可以进一步了解该方法所在类TypeSymbol
的用法示例。
在下文中一共展示了TypeSymbol.IsNullableType方法的15个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于系统推荐出更棒的C#代码示例。
示例1: MakeAsOperator
private BoundExpression MakeAsOperator(
BoundAsOperator oldNode,
CSharpSyntaxNode syntax,
BoundExpression rewrittenOperand,
BoundTypeExpression rewrittenTargetType,
Conversion conversion,
TypeSymbol rewrittenType)
{
// TODO: Handle dynamic operand type and target type
Debug.Assert(rewrittenTargetType.Type.Equals(rewrittenType));
// target type cannot be a non-nullable value type
Debug.Assert(!rewrittenType.IsValueType || rewrittenType.IsNullableType());
if (!_inExpressionLambda)
{
ConstantValue constantValue = Binder.GetAsOperatorConstantResult(rewrittenOperand.Type, rewrittenType, conversion.Kind, rewrittenOperand.ConstantValue);
if (constantValue != null)
{
Debug.Assert(constantValue.IsNull);
BoundExpression result = rewrittenType.IsNullableType() ? new BoundDefaultOperator(syntax, rewrittenType) : MakeLiteral(syntax, constantValue, rewrittenType);
if (rewrittenOperand.ConstantValue != null)
{
// No need to preserve any side-effects from the operand.
// We also can keep the "constant" notion of the result, which
// enables some optimizations down the road.
return result;
}
return new BoundSequence(
syntax: syntax,
locals: ImmutableArray<LocalSymbol>.Empty,
sideEffects: ImmutableArray.Create<BoundExpression>(rewrittenOperand),
value: result,
type: rewrittenType);
}
if (conversion.IsImplicit)
{
// Operand with bound implicit conversion to target type.
// We don't need a runtime check, generate a conversion for the operand instead.
return MakeConversionNode(syntax, rewrittenOperand, conversion, rewrittenType, @checked: false);
}
}
return oldNode.Update(rewrittenOperand, rewrittenTargetType, conversion, rewrittenType);
}
示例2: MakeAsOperator
private BoundExpression MakeAsOperator(
BoundAsOperator oldNode,
CSharpSyntaxNode syntax,
BoundExpression rewrittenOperand,
BoundTypeExpression rewrittenTargetType,
Conversion conversion,
TypeSymbol rewrittenType)
{
// TODO: Handle dynamic operand type and target type
Debug.Assert(rewrittenTargetType.Type.Equals(rewrittenType));
// target type cannot be a non-nullable value type
Debug.Assert(!rewrittenType.IsValueType || rewrittenType.IsNullableType());
if (!inExpressionLambda)
{
ConstantValue constantValue = Binder.GetAsOperatorConstantResult(rewrittenOperand.Type, rewrittenType, conversion.Kind, rewrittenOperand.ConstantValue);
Debug.Assert(constantValue == null || constantValue.IsNull);
if (conversion.IsImplicit)
{
// Operand with bound implicit conversion to target type.
// We don't need a runtime check, generate a conversion for the operand instead.
return MakeConversion(syntax, rewrittenOperand, conversion, rewrittenType, @checked: false, constantValueOpt: constantValue);
}
else if (constantValue != null)
{
return new BoundSequence(
syntax: syntax,
locals: ImmutableArray<LocalSymbol>.Empty,
sideEffects: ImmutableArray.Create<BoundExpression>(rewrittenOperand),
value: MakeLiteral(syntax, constantValue, rewrittenType),
type: rewrittenType);
}
}
return oldNode.Update(rewrittenOperand, rewrittenTargetType, conversion, rewrittenType);
}
示例3: CheckConstraints
// See TypeBind::CheckSingleConstraint.
private static bool CheckConstraints(
Symbol containingSymbol,
ConversionsBase conversions,
TypeMap substitution,
TypeParameterSymbol typeParameter,
TypeSymbol typeArgument,
Compilation currentCompilation,
ArrayBuilder<TypeParameterDiagnosticInfo> diagnosticsBuilder,
ref ArrayBuilder<TypeParameterDiagnosticInfo> useSiteDiagnosticsBuilder,
HashSet<TypeParameterSymbol> ignoreTypeConstraintsDependentOnTypeParametersOpt)
{
Debug.Assert(substitution != null);
// The type parameters must be original definitions of type parameters from the containing symbol.
Debug.Assert(ReferenceEquals(typeParameter.ContainingSymbol, containingSymbol.OriginalDefinition));
if (typeArgument.IsErrorType())
{
return true;
}
if (typeArgument.IsPointerType() || typeArgument.IsRestrictedType() || typeArgument.SpecialType == SpecialType.System_Void)
{
// "The type '{0}' may not be used as a type argument"
diagnosticsBuilder.Add(new TypeParameterDiagnosticInfo(typeParameter, new CSDiagnosticInfo(ErrorCode.ERR_BadTypeArgument, typeArgument)));
return false;
}
if (typeArgument.IsStatic)
{
// "'{0}': static types cannot be used as type arguments"
diagnosticsBuilder.Add(new TypeParameterDiagnosticInfo(typeParameter, new CSDiagnosticInfo(ErrorCode.ERR_GenericArgIsStaticClass, typeArgument)));
return false;
}
if (typeParameter.HasReferenceTypeConstraint && !typeArgument.IsReferenceType)
{
// "The type '{2}' must be a reference type in order to use it as parameter '{1}' in the generic type or method '{0}'"
diagnosticsBuilder.Add(new TypeParameterDiagnosticInfo(typeParameter, new CSDiagnosticInfo(ErrorCode.ERR_RefConstraintNotSatisfied, containingSymbol.ConstructedFrom(), typeParameter, typeArgument)));
return false;
}
if (typeParameter.HasValueTypeConstraint && !typeArgument.IsNonNullableValueType())
{
// "The type '{2}' must be a non-nullable value type in order to use it as parameter '{1}' in the generic type or method '{0}'"
diagnosticsBuilder.Add(new TypeParameterDiagnosticInfo(typeParameter, new CSDiagnosticInfo(ErrorCode.ERR_ValConstraintNotSatisfied, containingSymbol.ConstructedFrom(), typeParameter, typeArgument)));
return false;
}
// The type parameters for a constructed type/method are the type parameters of
// the ConstructedFrom type/method, so the constraint types are not substituted.
// For instance with "class C<T, U> where T : U", the type parameter for T in "C<object, int>"
// has constraint "U", not "int". We need to substitute the constraints from the
// original definition of the type parameters using the map from the constructed symbol.
var constraintTypes = ArrayBuilder<TypeSymbol>.GetInstance();
HashSet<DiagnosticInfo> useSiteDiagnostics = null;
substitution.SubstituteTypesDistinctWithoutModifiers(typeParameter.ConstraintTypesWithDefinitionUseSiteDiagnostics(ref useSiteDiagnostics), constraintTypes,
ignoreTypeConstraintsDependentOnTypeParametersOpt);
bool hasError = false;
foreach (var constraintType in constraintTypes)
{
if (SatisfiesConstraintType(conversions, typeArgument, constraintType, ref useSiteDiagnostics))
{
continue;
}
ErrorCode errorCode;
if (typeArgument.IsReferenceType)
{
errorCode = ErrorCode.ERR_GenericConstraintNotSatisfiedRefType;
}
else if (typeArgument.IsNullableType())
{
errorCode = constraintType.IsInterfaceType() ? ErrorCode.ERR_GenericConstraintNotSatisfiedNullableInterface : ErrorCode.ERR_GenericConstraintNotSatisfiedNullableEnum;
}
else if (typeArgument.TypeKind == TypeKind.TypeParameter)
{
errorCode = ErrorCode.ERR_GenericConstraintNotSatisfiedTyVar;
}
else
{
errorCode = ErrorCode.ERR_GenericConstraintNotSatisfiedValType;
}
SymbolDistinguisher distinguisher = new SymbolDistinguisher(currentCompilation, constraintType, typeArgument);
diagnosticsBuilder.Add(new TypeParameterDiagnosticInfo(typeParameter, new CSDiagnosticInfo(errorCode, containingSymbol.ConstructedFrom(), distinguisher.First, typeParameter, distinguisher.Second)));
hasError = true;
}
if (AppendUseSiteDiagnostics(useSiteDiagnostics, typeParameter, ref useSiteDiagnosticsBuilder))
{
hasError = true;
}
constraintTypes.Free();
// Check the constructor constraint.
if (typeParameter.HasConstructorConstraint && !SatisfiesConstructorConstraint(typeArgument))
//.........这里部分代码省略.........
示例4: 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;
}
示例5: TypeOrUnderlyingType
private TypeSymbol TypeOrUnderlyingType(TypeSymbol type)
{
if (type.IsNullableType())
{
return type.GetNullableUnderlyingType();
}
return type;
}
示例6: 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)
{
//.........这里部分代码省略.........
示例7: ClassifyNullLiteralConversion
private static ConversionKind ClassifyNullLiteralConversion(BoundExpression source, TypeSymbol destination)
{
Debug.Assert((object)source != null);
Debug.Assert((object)destination != null);
if (!source.IsLiteralNull())
{
return ConversionKind.NoConversion;
}
// SPEC: An implicit conversion exists from the null literal to any nullable type.
if (destination.IsNullableType())
{
// The spec defines a "null literal conversion" specifically as a conversion from
// null to nullable type.
return ConversionKind.NullLiteral;
}
// SPEC: An implicit conversion exists from the null literal to any reference type.
// SPEC: An implicit conversion exists from the null literal to type parameter T,
// SPEC: provided T is known to be a reference type. [...] The conversion [is] classified
// SPEC: as implicit reference conversion.
if (destination.IsReferenceType)
{
return ConversionKind.ImplicitReference;
}
// SPEC: The set of implicit conversions is extended to include...
// SPEC: ... from the null literal to any pointer type.
if (destination is PointerTypeSymbol)
{
return ConversionKind.NullToPointer;
}
return ConversionKind.NoConversion;
}
示例8: UserDefinedBinaryOperatorCanBeLifted
private static LiftingResult UserDefinedBinaryOperatorCanBeLifted(TypeSymbol left, TypeSymbol right, TypeSymbol result, BinaryOperatorKind kind)
{
// SPEC: For the binary operators + - * / % & | ^ << >> a lifted form of the
// SPEC: operator exists if the operand and result types are all non-nullable
// SPEC: value types. The lifted form is constructed by adding a single ?
// SPEC: modifier to each operand and result type.
//
// SPEC: For the equality operators == != a lifted form of the operator exists
// SPEC: if the operand types are both non-nullable value types and if the
// SPEC: result type is bool. The lifted form is constructed by adding
// SPEC: a single ? modifier to each operand type.
//
// SPEC: For the relational operators > < >= <= a lifted form of the
// SPEC: operator exists if the operand types are both non-nullable value
// SPEC: types and if the result type is bool. The lifted form is
// SPEC: constructed by adding a single ? modifier to each operand type.
if (!left.IsValueType ||
left.IsNullableType() ||
!right.IsValueType ||
right.IsNullableType())
{
return LiftingResult.NotLifted;
}
switch (kind)
{
case BinaryOperatorKind.Equal:
case BinaryOperatorKind.NotEqual:
// Spec violation: can't lift unless the types match.
// The spec doesn't require this, but dev11 does and it reduces ambiguity in some cases.
if (left != right) return LiftingResult.NotLifted;
goto case BinaryOperatorKind.GreaterThan;
case BinaryOperatorKind.GreaterThan:
case BinaryOperatorKind.GreaterThanOrEqual:
case BinaryOperatorKind.LessThan:
case BinaryOperatorKind.LessThanOrEqual:
return result.SpecialType == SpecialType.System_Boolean ?
LiftingResult.LiftOperandsButNotResult :
LiftingResult.NotLifted;
default:
return result.IsValueType && !result.IsNullableType() ?
LiftingResult.LiftOperandsAndResult :
LiftingResult.NotLifted;
}
}
示例9: 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;
}
示例10: 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);
}
}
示例11: 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;
}
示例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: SatisfiesConstraintType
private static bool SatisfiesConstraintType(
ConversionsBase conversions,
TypeSymbol typeArgument,
TypeSymbol constraintType,
ref HashSet<DiagnosticInfo> useSiteDiagnostics)
{
if (constraintType.IsErrorType())
{
return false;
}
// Spec 4.4.4 describes the valid conversions from
// type argument A to constraint type C:
// "An identity conversion (6.1.1).
// An implicit reference conversion (6.1.6). ..."
if (conversions.HasIdentityOrImplicitReferenceConversion(typeArgument, constraintType, ref useSiteDiagnostics))
{
return true;
}
// "... A boxing conversion (6.1.7), provided that type A is a non-nullable value type. ..."
// NOTE: we extend this to allow, for example, a conversion from Nullable<T> to object.
if (typeArgument.IsValueType &&
conversions.HasBoxingConversion(typeArgument.IsNullableType() ? ((NamedTypeSymbol)typeArgument).ConstructedFrom : typeArgument, constraintType, ref useSiteDiagnostics))
{
return true;
}
if (typeArgument.TypeKind == TypeKind.TypeParameter)
{
var typeParameter = (TypeParameterSymbol)typeArgument;
// "... An implicit reference, boxing, or type parameter conversion
// from type parameter A to C."
if (conversions.HasImplicitTypeParameterConversion(typeParameter, constraintType, ref useSiteDiagnostics))
{
return true;
}
// TypeBind::SatisfiesBound allows cases where one of the
// type parameter constraints satisfies the constraint.
foreach (var typeArgumentConstraint in typeParameter.ConstraintTypesWithDefinitionUseSiteDiagnostics(ref useSiteDiagnostics))
{
if (SatisfiesConstraintType(conversions, typeArgumentConstraint, constraintType, ref useSiteDiagnostics))
{
return true;
}
}
}
return false;
}