-
Notifications
You must be signed in to change notification settings - Fork 4.1k
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
Async-streams: allow pattern-based disposal in await using and foreach #32731
Changes from all commits
d772212
e3622a4
5945e59
1e16d7e
898aa41
e2d996c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -90,6 +90,7 @@ internal static BoundStatement BindUsingStatementOrDeclarationFromParts(SyntaxNo | |
AwaitableInfo awaitOpt = null; | ||
TypeSymbol declarationTypeOpt = null; | ||
MethodSymbol disposeMethodOpt = null; | ||
TypeSymbol awaitableTypeOpt = null; | ||
|
||
if (isExpression) | ||
{ | ||
|
@@ -117,11 +118,19 @@ internal static BoundStatement BindUsingStatementOrDeclarationFromParts(SyntaxNo | |
|
||
if (hasAwait) | ||
{ | ||
TypeSymbol taskType = originalBinder.Compilation.GetWellKnownType(WellKnownType.System_Threading_Tasks_ValueTask); | ||
hasErrors |= ReportUseSiteDiagnostics(taskType, diagnostics, awaitKeyword); | ||
BoundAwaitableValuePlaceholder placeholderOpt; | ||
if (awaitableTypeOpt is null) | ||
{ | ||
placeholderOpt = null; | ||
} | ||
else | ||
{ | ||
hasErrors |= ReportUseSiteDiagnostics(awaitableTypeOpt, diagnostics, awaitKeyword); | ||
placeholderOpt = new BoundAwaitableValuePlaceholder(syntax, awaitableTypeOpt).MakeCompilerGenerated(); | ||
} | ||
|
||
BoundExpression placeholder = new BoundAwaitableValuePlaceholder(syntax, taskType).MakeCompilerGenerated(); | ||
awaitOpt = originalBinder.BindAwaitInfo(placeholder, syntax, awaitKeyword.GetLocation(), diagnostics, ref hasErrors); | ||
// even if we don't have a proper value to await, we'll still report bad usages of `await` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 📝 an IDE test caught a regression. Even if there is no disposable type, we should report bad usage of |
||
awaitOpt = originalBinder.BindAwaitInfo(placeholderOpt, syntax, awaitKeyword.GetLocation(), diagnostics, ref hasErrors); | ||
} | ||
|
||
// This is not awesome, but its factored. | ||
|
@@ -146,6 +155,7 @@ internal static BoundStatement BindUsingStatementOrDeclarationFromParts(SyntaxNo | |
hasErrors); | ||
} | ||
|
||
// initializes iDisposableConversion, awaitableTypeOpt and disposeMethodOpt | ||
bool populateDisposableConversionOrDisposeMethod(bool fromExpression) | ||
{ | ||
HashSet<DiagnosticInfo> useSiteDiagnostics = null; | ||
|
@@ -155,14 +165,18 @@ bool populateDisposableConversionOrDisposeMethod(bool fromExpression) | |
|
||
if (iDisposableConversion.IsImplicit) | ||
{ | ||
if (hasAwait) | ||
{ | ||
awaitableTypeOpt = originalBinder.Compilation.GetWellKnownType(WellKnownType.System_Threading_Tasks_ValueTask); | ||
} | ||
return true; | ||
} | ||
|
||
TypeSymbol type = fromExpression ? expressionOpt.Type : declarationTypeOpt; | ||
|
||
// If this is a ref struct, try binding via pattern. | ||
// If this is a ref struct, or we're in a valid asynchronous using, try binding via pattern. | ||
// We won't need to try and bind a second time if it fails, as async dispose can't be pattern based (ref structs are not allowed in async methods) | ||
if (!(type is null) && type.IsValueType && type.IsRefLikeType) | ||
if (!(type is null) && (type.IsRefLikeType || hasAwait)) | ||
{ | ||
BoundExpression receiver = fromExpression | ||
? expressionOpt | ||
|
@@ -171,6 +185,10 @@ bool populateDisposableConversionOrDisposeMethod(bool fromExpression) | |
disposeMethodOpt = originalBinder.TryFindDisposePatternMethod(receiver, syntax, hasAwait, diagnostics); | ||
if (!(disposeMethodOpt is null)) | ||
{ | ||
if (hasAwait) | ||
{ | ||
awaitableTypeOpt = disposeMethodOpt.ReturnType.TypeSymbol; | ||
} | ||
return true; | ||
} | ||
} | ||
|
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The
disposeMethod
is discarded here but what about any diagnostics that resulted from callingPerformPatternMethodLookup
? Won't those still be indiagnostics
and hence passed back up to the caller?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the
using
scenarios, we keep those diagnostics and add another error (didn't find a proper way of disposing). SeeUsingPatternScopedExtensionMethodTest
, which produces some unnecessary diagnostics. I'm thinking to leave that as-is for now, with tracking issue.In the
foreach
scenarios, the caller already uses a separate diagnostic bag. I'll add tests to demonstrate.