-
Notifications
You must be signed in to change notification settings - Fork 4k
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
Added support for implicitly-typed out variables. #11493
Changes from all commits
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 |
---|---|---|
|
@@ -168,6 +168,18 @@ internal virtual ImmutableArray<LocalFunctionSymbol> GetDeclaredLocalFunctionsFo | |
return this.Next.GetDeclaredLocalFunctionsForScope(scopeDesignator); | ||
} | ||
|
||
/// <summary> | ||
/// If this binder owns a scope for locals, return syntax node that is used | ||
/// as the scope designator. Otherwise, null. | ||
/// </summary> | ||
internal virtual SyntaxNode ScopeDesignator | ||
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. Does this correspond to the concept of scope designator as produced by the compiler in support of E&C? 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. I am not sure what are you referring to. This is a concept that binder uses internally in a couple of related APIs. |
||
{ | ||
get | ||
{ | ||
return null; | ||
} | ||
} | ||
|
||
internal virtual bool IsLocalFunctionsScopeBinder | ||
{ | ||
get | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1369,12 +1369,43 @@ private BoundExpression BindNonMethod(SimpleNameSyntax node, Symbol symbol, Diag | |
} | ||
else | ||
{ | ||
SourceLocalSymbol sourceLocal; | ||
type = null; | ||
|
||
if (node.SyntaxTree == localSymbolLocation.SourceTree && (object)(sourceLocal = localSymbol as SourceLocalSymbol) != null && | ||
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. What's the difference with the simpler check "sourceLocal is SourceLocalSymbol"? #Closed 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. |
||
sourceLocal.IdentifierToken.Parent?.Kind() == SyntaxKind.Argument) | ||
{ | ||
var argument = (ArgumentSyntax)sourceLocal.IdentifierToken.Parent; | ||
|
||
if (argument.Identifier == sourceLocal.IdentifierToken && | ||
argument.Type.IsVar) | ||
{ | ||
// We are referring to an out variable which might need type inference. | ||
// If it is in fact needs inference, it is illegal to reference it in the same argument list that immediately | ||
// contains its declaration. | ||
// Technically, we could support some restricted scenarios (when it is used as another argument in the same list), | ||
// but their utility is very questionable. Otherwise, we are looking into getting into a cycle trying to infer its type. | ||
if (node.SpanStart < ((ArgumentListSyntax)argument.Parent).CloseParenToken.SpanStart && | ||
sourceLocal.IsVar) // This check involves trying to bind 'var' as a real type, so keeping it last for performance. | ||
{ | ||
Error(diagnostics, ErrorCode.ERR_ImplicitlyTypedOutVariableUsedInTheSameArgumentList, node, node); | ||
|
||
// Treat this case as variable used before declaration, we might be able to infer type of the variable anyway and SemanticModel | ||
// will be able to return non-error type information for this node. | ||
type = new ExtendedErrorTypeSymbol(this.Compilation, name: "var", arity: 0, errorInfo: null, variableUsedBeforeDeclaration: true); | ||
} | ||
} | ||
} | ||
|
||
if ((object)type == null) | ||
{ | ||
type = localSymbol.Type; | ||
} | ||
|
||
if (IsBadLocalOrParameterCapture(localSymbol, localSymbol.RefKind)) | ||
{ | ||
Error(diagnostics, ErrorCode.ERR_AnonDelegateCantUseLocal, node, localSymbol); | ||
} | ||
|
||
type = localSymbol.Type; | ||
} | ||
|
||
return new BoundLocal(node, localSymbol, constantValueOpt, type, hasErrors: isError); | ||
|
@@ -2121,10 +2152,21 @@ private BoundExpression BindArgumentValue(DiagnosticBag diagnostics, ArgumentSyn | |
this.ValidateDeclarationNameConflictsInScope(localSymbol, diagnostics); | ||
} | ||
|
||
if (this.InConstructorInitializer) | ||
{ | ||
Error(diagnostics, ErrorCode.ERR_OutVarInConstructorInitializer, argumentSyntax.Identifier); | ||
} | ||
|
||
if (isVar) | ||
{ | ||
// PROTOTYPE(outvar): | ||
throw new NotImplementedException(); | ||
return new OutVarLocalPendingInference(argumentSyntax, localSymbol); | ||
} | ||
|
||
if (this.ContainingMemberOrLambda.Kind == SymbolKind.Method | ||
&& ((MethodSymbol)this.ContainingMemberOrLambda).IsAsync | ||
&& declType.IsRestrictedType()) | ||
{ | ||
Error(diagnostics, ErrorCode.ERR_BadSpecialByRefLocal, argumentSyntax.Type, declType); | ||
} | ||
|
||
return new BoundLocal(argumentSyntax, localSymbol, constantValueOpt: null, type: declType); | ||
|
@@ -2280,6 +2322,21 @@ private BoundExpression BindArgumentExpression(DiagnosticBag diagnostics, Expres | |
|
||
arguments[arg] = CreateConversion(argument.Syntax, argument, kind, false, type, diagnostics); | ||
} | ||
else if (argument.Kind == BoundKind.OutVarLocalPendingInference) | ||
{ | ||
TypeSymbol parameterType = GetCorrespondingParameterType(ref result, parameters, arg); | ||
bool hasErrors = false; | ||
|
||
if (this.ContainingMemberOrLambda.Kind == SymbolKind.Method | ||
&& ((MethodSymbol)this.ContainingMemberOrLambda).IsAsync | ||
&& parameterType.IsRestrictedType()) | ||
{ | ||
Error(diagnostics, ErrorCode.ERR_BadSpecialByRefLocal, ((ArgumentSyntax)argument.Syntax).Type, parameterType); | ||
hasErrors = true; | ||
} | ||
|
||
arguments[arg] = ((OutVarLocalPendingInference)argument).SetInferredType(parameterType, success: !hasErrors); | ||
} | ||
} | ||
} | ||
|
||
|
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.
You said that this is an open issue ("I think it is worth to take another look at the issue at LDM and confirm whether we still want to stick with the current decision."). Please place it on the open issue list.
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.
I will do this separately. I am planning to move open issue in a special GitHub Issue. I think that would provide more flexibility.
In reply to: 64253175 [](ancestors = 64253175)