Skip to content

Commit

Permalink
Fix error recovery for various nested conversion scenarios (#74089)
Browse files Browse the repository at this point in the history
  • Loading branch information
RikkiGibson authored Jun 27, 2024
1 parent 1c83ce1 commit 9951ceb
Show file tree
Hide file tree
Showing 4 changed files with 371 additions and 7 deletions.
8 changes: 6 additions & 2 deletions src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -708,6 +708,7 @@ private BoundCollectionExpression ConvertCollectionExpression(
diagnostics);
builder.Add(convertedElement!);
}
conversion.MarkUnderlyingConversionsChecked();
}

return new BoundCollectionExpression(
Expand Down Expand Up @@ -1644,7 +1645,8 @@ private BoundExpression ConvertConditionalExpression(
{
bool targetTyped = conversionIfTargetTyped is { };
Debug.Assert(targetTyped || destination.IsErrorType() || destination.Equals(source.Type, TypeCompareKind.ConsiderEverything));
ImmutableArray<Conversion> underlyingConversions = conversionIfTargetTyped.GetValueOrDefault().UnderlyingConversions;
var conversion = conversionIfTargetTyped.GetValueOrDefault();
ImmutableArray<Conversion> underlyingConversions = conversion.UnderlyingConversions;
var condition = source.Condition;
hasErrors |= source.HasErrors || destination.IsErrorType();

Expand All @@ -1656,6 +1658,7 @@ private BoundExpression ConvertConditionalExpression(
targetTyped
? CreateConversion(source.Alternative.Syntax, source.Alternative, underlyingConversions[1], isCast: false, conversionGroupOpt: null, destination, diagnostics)
: GenerateConversionForAssignment(destination, source.Alternative, diagnostics);
conversion.MarkUnderlyingConversionsChecked();
var constantValue = FoldConditionalOperator(condition, trueExpr, falseExpr);
hasErrors |= constantValue?.IsBad == true;
if (targetTyped && !destination.IsErrorType() && !Compilation.IsFeatureEnabled(MessageID.IDS_FeatureTargetTypedConditional))
Expand Down Expand Up @@ -1695,6 +1698,7 @@ private BoundExpression ConvertSwitchExpression(BoundUnconvertedSwitchExpression
new BoundSwitchExpressionArm(oldCase.Syntax, oldCase.Locals, oldCase.Pattern, oldCase.WhenClause, newValue, oldCase.Label, oldCase.HasErrors);
builder.Add(newCase);
}
conversion.MarkUnderlyingConversionsChecked();

var newSwitchArms = builder.ToImmutableAndFree();
return new BoundConvertedSwitchExpression(
Expand Down Expand Up @@ -1723,7 +1727,7 @@ private BoundExpression CreateUserDefinedConversion(

return new BoundConversion(
syntax,
source,
BindToNaturalType(source, diagnostics),
conversion,
CheckOverflowAtRuntime,
explicitCastInCode: isCast,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7184,7 +7184,7 @@ private void VisitArgumentConversionAndInboundAssignmentsAndPreConditions(
case RefKind.In:
{
// Note: for lambda arguments, they will be converted in the context/state we saved for that argument
if (conversion is { Kind: ConversionKind.ImplicitUserDefined })
if (conversion is { IsValid: true, Kind: ConversionKind.ImplicitUserDefined })
{
var argumentResultType = resultType.Type;
conversion = GenerateConversion(_conversions, argumentNoConversion, argumentResultType, parameterType.Type, fromExplicitCast: false, extensionMethodThisArgument: false, isChecked: conversionOpt?.Checked ?? false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -917,10 +917,12 @@ private void VisitSwitchExpressionCore(BoundSwitchExpression node, bool inferTyp

if (inferType && inferredType is null)
{
// This can happen when we're inferring the return type of a lambda, or when there are no arms (an error case).
// For this case, we don't need to do any work, as the unconverted switch expression can't contribute info, and
// there is nothing that is being publicly exposed to the semantic model.
Debug.Assert((node is BoundUnconvertedSwitchExpression && _returnTypesOpt is not null)
// This can happen when we're inferring the return type of a lambda or visiting a node without diagnostics like
// BoundConvertedTupleLiteral.SourceTuple. For these cases, we don't need to do any work,
// the unconverted switch expression can't contribute info. The conversion that should be on top of this
// can add or remove nullability, and nested nodes aren't being publicly exposed by the semantic model.
// See also NullableWalker.VisitConditionalOperatorCore for a similar check for conditional operators.
Debug.Assert((node is BoundUnconvertedSwitchExpression && (_returnTypesOpt is not null || _disableDiagnostics))
|| node is BoundSwitchExpression { SwitchArms: { Length: 0 } });
inferredState = default;

Expand Down
Loading

0 comments on commit 9951ceb

Please sign in to comment.