Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rebase target-typed-new branch on top of master #39658

Merged
merged 46 commits into from
Mar 6, 2020
Merged
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
e3346a7
Rebase target-typed-new branch on top of master
alrz Nov 3, 2019
c91b8a9
Fix formatting
alrz Nov 4, 2019
6e801fe
Move method
alrz Nov 4, 2019
1e02465
Adjust baseline
alrz Nov 4, 2019
e565cf2
Revert formatting
alrz Dec 18, 2019
99f386d
Fix switch label binding
alrz Dec 18, 2019
a731674
Revert code
alrz Dec 18, 2019
f4ca425
Clarify diagnostics
alrz Dec 18, 2019
73c9824
Update resources
alrz Dec 18, 2019
4a362d2
Add comment
alrz Dec 18, 2019
fc55e5e
Revert code
alrz Dec 18, 2019
8e6d3e0
Explicit type parsing mode to avoid superfluous diagnostics
alrz Dec 19, 2019
ccee382
Bind to natrual type so the node cannot sneak into a later pass
alrz Dec 19, 2019
067bf52
Clarify comment on binary operator resolution
alrz Dec 19, 2019
fac36f2
Add suggested tests
alrz Dec 19, 2019
c12c38c
Update compiler test plan
alrz Dec 19, 2019
d660443
Fix tuple equality
alrz Dec 19, 2019
b421d5c
Fix typo
alrz Dec 19, 2019
8fbe7fa
Test conditional access
alrz Dec 24, 2019
965c50c
Renamings
alrz Jan 7, 2020
c415912
Merge remote-tracking branch 'origin/master' into target-typed-new
alrz Jan 7, 2020
cff10ef
Fixup merge
alrz Jan 7, 2020
471dfce
Fixup tests
alrz Jan 9, 2020
1522da4
Merge remote-tracking branch 'origin/master' into target-typed-new
alrz Jan 29, 2020
a1fc531
Update resources
alrz Jan 29, 2020
14a7dc9
Regenerate compiler code
alrz Jan 29, 2020
e6a448f
Fixup merge
alrz Jan 29, 2020
85ec0a7
Merge remote-tracking branch 'origin/master' into target-typed-new
alrz Feb 11, 2020
456666b
Revert code
alrz Feb 11, 2020
0ae0f80
Capture use-site diagnostics
alrz Feb 11, 2020
aa48a61
Tweaks
alrz Feb 11, 2020
e19c690
Fix formatting
alrz Feb 11, 2020
b97cac0
Address PR feedback on tests
alrz Feb 11, 2020
c082eff
Undo accidental insertion
alrz Feb 11, 2020
e49bc5e
Fix build
alrz Feb 11, 2020
9492d27
Merge remote-tracking branch 'origin/master' into target-typed-new
alrz Feb 20, 2020
78613a4
Use Display string for every argument expression
alrz Feb 20, 2020
5461453
Update baseline
alrz Feb 20, 2020
0823903
Update resources
alrz Feb 20, 2020
49887e7
Permit throw new() usage
alrz Feb 20, 2020
c6aba72
Add wasTargetTyped flag for object creation node
alrz Feb 20, 2020
c0e7d27
PR feedback
alrz Feb 26, 2020
a551583
Merge remote-tracking branch 'origin/master' into target-typed-new
alrz Feb 26, 2020
b9e2751
Fix merge
alrz Feb 26, 2020
6a10fce
Revert nullable enable
alrz Feb 27, 2020
4961ff1
Argument list is not optional in new()
alrz Feb 27, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/contributing/Compiler Test Plan.md
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ a[e]
x++
x--
new X()
new()
typeof(T)
default(T)
default
Expand Down
63 changes: 63 additions & 0 deletions src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,11 @@ protected BoundExpression CreateConversion(
}
}

if (conversion.IsObjectCreation)
{
return ConvertObjectCreationExpression((BoundUnconvertedObjectCreationExpression)source, isCast, destination, diagnostics);
}

if (conversion.IsUserDefined)
{
// User-defined conversions are likely to be represented as multiple
Expand Down Expand Up @@ -152,6 +157,64 @@ protected BoundExpression CreateConversion(
{ WasCompilerGenerated = wasCompilerGenerated };
}

private BoundExpression ConvertObjectCreationExpression(BoundUnconvertedObjectCreationExpression node, bool isCast, TypeSymbol destination, DiagnosticBag diagnostics)
{
var arguments = AnalyzedArguments.GetInstance(node.Arguments, node.ArgumentRefKindsOpt, node.ArgumentNamesOpt);
BoundExpression expr = BindObjectCreationExpression(node, destination.StrippedType(), arguments, diagnostics);
if (destination.IsNullableType())
{
// We manually create an ImplicitNullable conversion
// if the destination is nullable, in which case we
// target the underlying type e.g. `S? x = new();`
// is actually identical to `S? x = new S();`.
Copy link
Member

@jcouv jcouv Dec 17, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is actually identical to S? x = new S();. [](start = 19, length = 43)

📝 let's remember to capture that in speclet #Closed

var conversion = new Conversion(ConversionKind.ImplicitNullable, Conversion.IdentityUnderlying);
333fred marked this conversation as resolved.
Show resolved Hide resolved
expr = new BoundConversion(
node.Syntax,
operand: expr,
conversion: conversion,
@checked: false,
explicitCastInCode: isCast,
conversionGroupOpt: new ConversionGroup(conversion),
Copy link
Contributor Author

@alrz alrz Dec 24, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't want the ObjectCreation conversion to be picked up by nullable walker, so the the conversion group has to be backwards.. (I noticed there's a plan to remove this #27163) #Closed

Copy link
Member

@333fred 333fred Feb 4, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure what backwards means here? Honestly, we can probably close #27163, I don't think we'll be removing ConversionGroup. #Closed

Copy link
Member

@333fred 333fred Feb 4, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Talking with @cston, I'm going to close that issue. ConversionGroup is here to stay. #Closed

constantValueOpt: expr.ConstantValue,
type: destination);
}
arguments.Free();
return expr;
}

private BoundExpression BindObjectCreationExpression(BoundUnconvertedObjectCreationExpression node, TypeSymbol type, AnalyzedArguments arguments, DiagnosticBag diagnostics)
{
var syntax = node.Syntax;
switch (type.TypeKind)
{
case TypeKind.Struct:
case TypeKind.Class when !type.IsAnonymousType: // We don't want to enable object creation with unspeakable types
return BindClassCreationExpression(syntax, type.Name, typeNode: syntax, (NamedTypeSymbol)type, arguments, diagnostics, node.InitializerOpt);
case TypeKind.TypeParameter:
return BindTypeParameterCreationExpression(syntax, (TypeParameterSymbol)type, arguments, node.InitializerOpt, typeSyntax: syntax, diagnostics);
case TypeKind.Delegate:
return BindDelegateCreationExpression(syntax, (NamedTypeSymbol)type, arguments, node.InitializerOpt, diagnostics);
case TypeKind.Array:
case TypeKind.Enum:
case TypeKind.Class:
Error(diagnostics, ErrorCode.ERR_TypelessNewIllegalTargetType, syntax, type);
alrz marked this conversation as resolved.
Show resolved Hide resolved
goto case TypeKind.Error;
case TypeKind.Interface:
Error(diagnostics, ErrorCode.ERR_NoNewAbstract, syntax, type);
goto case TypeKind.Error;
case TypeKind.Pointer:
Error(diagnostics, ErrorCode.ERR_UnsafeTypeInObjectCreation, syntax, type);
goto case TypeKind.Error;
case TypeKind.Dynamic:
Error(diagnostics, ErrorCode.ERR_NoConstructors, syntax, type);
goto case TypeKind.Error;
case TypeKind.Error:
return MakeBadExpressionForObjectCreation(syntax, type, arguments, node.InitializerOpt, typeSyntax: syntax, diagnostics);
case var v:
throw ExceptionUtilities.UnexpectedValue(v);
}
}

#nullable enable
/// <summary>
/// Rewrite the expressions in the switch expression arms to add a conversion to the destination type.
Expand Down
381 changes: 207 additions & 174 deletions src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -1548,6 +1548,7 @@ private BoundExpression BindNameofOperatorInternal(InvocationExpressionSyntax no
}
}

boundArgument = BindToNaturalType(boundArgument, diagnostics, reportNoTargetType: false);
return new BoundNameOfOperator(node, boundArgument, ConstantValue.Create(name), Compilation.GetSpecialType(SpecialType.System_String));
}

Expand Down
45 changes: 31 additions & 14 deletions src/Compilers/CSharp/Portable/Binder/Binder_Operators.cs
Original file line number Diff line number Diff line change
Expand Up @@ -587,8 +587,8 @@ private BoundExpression BindSimpleBinaryOperator(BinaryExpressionSyntax node, Di
{
// If we found an operator, we'll have given the `default` literal a type.
// Otherwise, we'll have reported the problem in ReportBinaryOperatorError.
resultLeft = BindToNaturalType(resultLeft, diagnostics, reportDefaultMissingType: false);
resultRight = BindToNaturalType(resultRight, diagnostics, reportDefaultMissingType: false);
resultLeft = BindToNaturalType(resultLeft, diagnostics, reportNoTargetType: false);
resultRight = BindToNaturalType(resultRight, diagnostics, reportNoTargetType: false);
}

hasErrors = hasErrors || resultConstant != null && resultConstant.IsBad;
Expand Down Expand Up @@ -653,8 +653,8 @@ private bool BindSimpleBinaryOperatorParts(BinaryExpressionSyntax node, Diagnost
{
resultSignature = signature;
HashSet<DiagnosticInfo> useSiteDiagnostics = null;
bool leftDefault = left.IsLiteralDefault();
bool rightDefault = right.IsLiteralDefault();
bool leftDefault = left.IsLiteralDefaultOrTypelessNew();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

left.IsLiteralDefaultOrTypelessNew(); [](start = 39, length = 37)

📝 let's make sure that the speclet captures the rules around new() and comparisons (when is object equality valid?)

bool rightDefault = right.IsLiteralDefaultOrTypelessNew();
foundOperator = !isObjectEquality || BuiltInOperators.IsValidObjectEquality(Conversions, leftType, leftNull, leftDefault, rightType, rightNull, rightDefault, ref useSiteDiagnostics);
diagnostics.Add(node, useSiteDiagnostics);
}
Expand Down Expand Up @@ -699,18 +699,20 @@ private static void ReportBinaryOperatorError(ExpressionSyntax node, DiagnosticB
{
bool leftDefault = left.IsLiteralDefault();
bool rightDefault = right.IsLiteralDefault();
if ((operatorToken.Kind() == SyntaxKind.EqualsEqualsToken || operatorToken.Kind() == SyntaxKind.ExclamationEqualsToken))
if (operatorToken.Kind() != SyntaxKind.EqualsEqualsToken && operatorToken.Kind() != SyntaxKind.ExclamationEqualsToken)
{
if (leftDefault && rightDefault)
if (leftDefault || rightDefault)
{
Error(diagnostics, ErrorCode.ERR_AmbigBinaryOpsOnDefault, node, operatorToken.Text);
// other than == and !=, binary operators are disallowed on `default` literal
Error(diagnostics, ErrorCode.ERR_BadOpOnNullOrDefaultOrNew, node, operatorToken.Text, "default");
return;
}
}
else if (leftDefault || rightDefault)

if ((leftDefault || left.IsTypelessNew()) &&
(rightDefault || right.IsTypelessNew()))
{
// other than == and !=, binary operators are disallowed on `default` literal
Error(diagnostics, ErrorCode.ERR_BadOpOnNullOrDefault, node, operatorToken.Text, "default");
Error(diagnostics, ErrorCode.ERR_AmbigBinaryOpsOnDefaultOrNew, node, operatorToken.Text, left.Display, right.Display);
return;
}

Expand Down Expand Up @@ -1113,7 +1115,7 @@ private TypeSymbol GetBinaryOperatorErrorType(BinaryOperatorKind kind, Diagnosti

private BinaryOperatorAnalysisResult BinaryOperatorOverloadResolution(BinaryOperatorKind kind, BoundExpression left, BoundExpression right, CSharpSyntaxNode node, DiagnosticBag diagnostics, out LookupResultKind resultKind, out ImmutableArray<MethodSymbol> originalUserDefinedOperators)
{
if (!IsDefaultLiteralAllowedInBinaryOperator(kind, left, right))
if (!IsTypelessExpressionAllowedInBinaryOperator(kind, left, right))
{
resultKind = LookupResultKind.OverloadResolutionFailure;
originalUserDefinedOperators = default(ImmutableArray<MethodSymbol>);
Expand Down Expand Up @@ -1182,8 +1184,21 @@ private void ReportObsoleteAndFeatureAvailabilityDiagnostics(MethodSymbol operat
}
}

private bool IsDefaultLiteralAllowedInBinaryOperator(BinaryOperatorKind kind, BoundExpression left, BoundExpression right)
private bool IsTypelessExpressionAllowedInBinaryOperator(BinaryOperatorKind kind, BoundExpression left, BoundExpression right)
{
// The default literal is only allowed with equality operators and both operands cannot be typeless at the same time.
// Note: we only need to restrict expressions that can be converted to *any* type, in which case the resolution could always succeed.

if (left.IsTypelessNew())
{
return !right.IsLiteralDefaultOrTypelessNew();
alrz marked this conversation as resolved.
Show resolved Hide resolved
}

if (right.IsTypelessNew())
{
return !left.IsLiteralDefault();
}

bool isEquality = kind == BinaryOperatorKind.Equal || kind == BinaryOperatorKind.NotEqual;
if (isEquality)
{
Expand Down Expand Up @@ -2313,7 +2328,7 @@ private BoundExpression BindUnaryOperatorCore(CSharpSyntaxNode node, string oper
{
// Dev10 does not allow unary prefix operators to be applied to the null literal
// (or other typeless expressions).
Error(diagnostics, ErrorCode.ERR_BadOpOnNullOrDefault, node, operatorText, operand.Display);
Error(diagnostics, ErrorCode.ERR_BadOpOnNullOrDefaultOrNew, node, operatorText, operand.Display);
}

// If the operand is bad, avoid generating cascading errors.
Expand Down Expand Up @@ -3420,7 +3435,7 @@ private BoundExpression BindNullCoalescingOperator(BinaryExpressionSyntax node,
// The specification does not permit the left hand side to be a default literal
if (leftOperand.IsLiteralDefault())
{
Error(diagnostics, ErrorCode.ERR_BadOpOnNullOrDefault, node, node.OperatorToken.Text, "default");
Error(diagnostics, ErrorCode.ERR_BadOpOnNullOrDefaultOrNew, node, node.OperatorToken.Text, "default");

return new BoundNullCoalescingOperator(node, leftOperand, rightOperand,
Conversion.NoConversion, BoundNullCoalescingOperatorResultKind.NoCommonType, CreateErrorType(), hasErrors: true);
Expand Down Expand Up @@ -3862,6 +3877,8 @@ private BoundExpression BindConditionalOperator(ConditionalExpressionSyntax node
hasErrors = constantValue != null && constantValue.IsBad;
}

trueExpr = BindToNaturalType(trueExpr, diagnostics, reportNoTargetType: false);
falseExpr = BindToNaturalType(falseExpr, diagnostics, reportNoTargetType: false);
return new BoundConditionalOperator(node, isRef, condition, trueExpr, falseExpr, constantValue, type, hasErrors);
}

Expand Down
4 changes: 4 additions & 0 deletions src/Compilers/CSharp/Portable/Binder/Binder_Query.cs
Original file line number Diff line number Diff line change
Expand Up @@ -735,6 +735,10 @@ protected BoundCall MakeQueryInvocation(CSharpSyntaxNode node, BoundExpression r
{
diagnostics.Add(ErrorCode.ERR_DefaultLiteralNotValid, node.Location);
}
else if (ultimateReceiver.IsTypelessNew())
{
diagnostics.Add(ErrorCode.ERR_TypelessNewNotValid, node.Location);
}
else if (ultimateReceiver.Kind == BoundKind.NamespaceExpression)
{
diagnostics.Add(ErrorCode.ERR_BadSKunknown, ultimateReceiver.Syntax.Location, ultimateReceiver.Syntax, MessageID.IDS_SK_NAMESPACE.Localize());
Expand Down
7 changes: 7 additions & 0 deletions src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,13 @@ internal BoundStatement BindPossibleEmbeddedStatement(StatementSyntax node, Diag
private BoundExpression BindThrownExpression(ExpressionSyntax exprSyntax, DiagnosticBag diagnostics, ref bool hasErrors)
{
var boundExpr = BindValue(exprSyntax, diagnostics, BindValueKind.RValue);
if (boundExpr.IsTypelessNew())
{
// NOTE This only disallows direct usage. One can simply bypass this by wrapping new() in a switch expression
333fred marked this conversation as resolved.
Show resolved Hide resolved
diagnostics.Add(ErrorCode.ERR_TypelessNewNotValid, exprSyntax.Location);
hasErrors = true;
}

if (Compilation.LanguageVersion < MessageID.IDS_FeatureSwitchExpression.RequiredVersion())
{
// This is the pre-C# 8 algorithm for binding a thrown expression.
Expand Down
39 changes: 24 additions & 15 deletions src/Compilers/CSharp/Portable/Binder/Binder_TupleOperators.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ private BoundExpression ApplyConvertedTypes(BoundExpression expr, TupleBinaryOpe
var multiple = (TupleBinaryOperatorInfo.Multiple)@operator;
if (multiple.Operators.Length == 0)
{
return BindToNaturalType(expr, diagnostics, reportDefaultMissingType: false);
return BindToNaturalType(expr, diagnostics, reportNoTargetType: false);
}

ImmutableArray<BoundExpression> arguments = tuple.Arguments;
Expand All @@ -62,7 +62,7 @@ private BoundExpression ApplyConvertedTypes(BoundExpression expr, TupleBinaryOpe
}

// This element isn't getting a converted type
return BindToNaturalType(expr, diagnostics, reportDefaultMissingType: false);
return BindToNaturalType(expr, diagnostics, reportNoTargetType: false);
}

// We were able to determine a converted type (for this tuple literal or element), we can just convert to it
Expand Down Expand Up @@ -191,11 +191,11 @@ private TupleBinaryOperatorInfo BindTupleDynamicBinaryOperatorSingleInfo(BinaryE
private TupleBinaryOperatorInfo.Multiple BindTupleBinaryOperatorNestedInfo(BinaryExpressionSyntax node, BinaryOperatorKind kind,
BoundExpression left, BoundExpression right, DiagnosticBag diagnostics)
{
left = GiveTupleTypeToDefaultLiteralIfNeeded(left, right.Type);
right = GiveTupleTypeToDefaultLiteralIfNeeded(right, left.Type);
left = GiveTupleTypeToTypelessExpressionIfNeeded(left, right.Type, diagnostics);
right = GiveTupleTypeToTypelessExpressionIfNeeded(right, left.Type, diagnostics);

if ((left.Type is null && left.IsLiteralDefault()) ||
(right.Type is null && right.IsLiteralDefault()))
if ((left.Type is null && left.IsLiteralDefaultOrTypelessNew()) ||
(right.Type is null && right.IsLiteralDefaultOrTypelessNew()))
{
Error(diagnostics, ErrorCode.ERR_AmbigBinaryOps, node, node.OperatorToken.Text, left.Display, right.Display);
return TupleBinaryOperatorInfo.Multiple.ErrorInstance;
Expand Down Expand Up @@ -311,27 +311,36 @@ private static void ReportNamesMismatchesIfAny(BoundExpression left, BoundExpres
}
}

internal static BoundExpression GiveTupleTypeToDefaultLiteralIfNeeded(BoundExpression expr, TypeSymbol targetType)
internal BoundExpression GiveTupleTypeToTypelessExpressionIfNeeded(BoundExpression expr, TypeSymbol targetType, DiagnosticBag diagnostics)
{
if (!expr.IsLiteralDefault() || targetType is null)
if (targetType is object)
{
return expr;
if (expr.IsLiteralDefault())
{
Debug.Assert(targetType.StrippedType().IsTupleType);
return new BoundDefaultExpression(expr.Syntax, targetType);
}

if (expr is BoundUnconvertedObjectCreationExpression objectCreation)
{
return ConvertObjectCreationExpression(objectCreation, isCast: false, targetType, diagnostics);
}
}

Debug.Assert(targetType.StrippedType().IsTupleType);
return new BoundDefaultExpression(expr.Syntax, targetType);
return expr;
}

private static bool IsTupleBinaryOperation(BoundExpression left, BoundExpression right)
{
bool leftDefault = left.IsLiteralDefault();
bool rightDefault = right.IsLiteralDefault();
if (leftDefault && rightDefault)
bool leftDefaultOrNew = left.IsLiteralDefaultOrTypelessNew();
bool rightDefaultOrNew = right.IsLiteralDefaultOrTypelessNew();
if (leftDefaultOrNew && rightDefaultOrNew)
{
return false;
}

return (GetTupleCardinality(left) > 1 || leftDefault) && (GetTupleCardinality(right) > 1 || rightDefault);
return (GetTupleCardinality(left) > 1 || leftDefaultOrNew) &&
(GetTupleCardinality(right) > 1 || rightDefaultOrNew);
}

private static int GetTupleCardinality(BoundExpression expr)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,7 @@ internal static Conversion GetTrivialConversion(ConversionKind kind)
internal static Conversion ImplicitReference => new Conversion(ConversionKind.ImplicitReference);
internal static Conversion ImplicitEnumeration => new Conversion(ConversionKind.ImplicitEnumeration);
internal static Conversion ImplicitThrow => new Conversion(ConversionKind.ImplicitThrow);
internal static Conversion ObjectCreation => new Conversion(ConversionKind.ObjectCreation);
internal static Conversion AnonymousFunction => new Conversion(ConversionKind.AnonymousFunction);
internal static Conversion Boxing => new Conversion(ConversionKind.Boxing);
internal static Conversion NullLiteral => new Conversion(ConversionKind.NullLiteral);
Expand Down Expand Up @@ -521,6 +522,17 @@ public bool IsThrow
}
}

/// <summary>
/// Returns true if the conversion is an implicit object creation expression conversion.
/// </summary>
internal bool IsObjectCreation
{
get
{
return Kind == ConversionKind.ObjectCreation;
}
}

/// <summary>
/// Returns true if the conversion is an implicit switch expression conversion.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,5 +54,6 @@ internal enum ConversionKind : byte
PinnedObjectToPointer,

DefaultLiteral, // a conversion from a `default` literal to any type
ObjectCreation, // a conversion from a `new()` expression to any type
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ public static bool IsImplicitConversion(this ConversionKind conversionKind)
case Deconstruction:
case StackAllocToPointerType:
case StackAllocToSpanType:
case ObjectCreation:
return true;

case ExplicitNumeric:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -926,6 +926,9 @@ private Conversion ClassifyImplicitBuiltInConversionFromExpression(BoundExpressi

case BoundKind.ThrowExpression:
return Conversion.ImplicitThrow;

case BoundKind.UnconvertedObjectCreationExpression:
return Conversion.ObjectCreation;
}

return Conversion.NoConversion;
Expand Down
Loading