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

Add support for using alias = any_type. #50167

Merged
Merged
Show file tree
Hide file tree
Changes from 74 commits
Commits
Show all changes
85 commits
Select commit Hold shift + click to select a range
cdf67db
Add parsing of using aliases that point to types.
CyrusNajmabadi Dec 29, 2020
7acfeba
Update API surface.
CyrusNajmabadi Dec 29, 2020
ba290a2
Fix tests
CyrusNajmabadi Dec 30, 2020
4f970f5
Add parsing tests
CyrusNajmabadi Dec 30, 2020
538637f
Add binding support
CyrusNajmabadi Dec 30, 2020
b7adad3
Update IDE side.
CyrusNajmabadi Dec 30, 2020
b64aeac
Add semantic tests
CyrusNajmabadi Dec 30, 2020
984bf0f
Support functptr types
CyrusNajmabadi Dec 30, 2020
b492649
Disallow ref types
CyrusNajmabadi Dec 30, 2020
523de61
Merge remote-tracking branch 'upstream/main' into usingAliasType
CyrusNajmabadi Sep 9, 2021
28c54b4
Merge
CyrusNajmabadi Sep 9, 2021
eb37ef3
Merge remote-tracking branch 'upstream/main' into usingAliasType
CyrusNajmabadi Jan 14, 2023
dda5b30
Fix
CyrusNajmabadi Jan 14, 2023
a314010
Fix
CyrusNajmabadi Jan 14, 2023
c67a9a1
move more cases to type
CyrusNajmabadi Jan 14, 2023
aa49836
Move error
CyrusNajmabadi Jan 14, 2023
27c0fcd
Add unsafe modifier
CyrusNajmabadi Jan 14, 2023
af583bb
Bind with unsafe
CyrusNajmabadi Jan 14, 2023
e2a1d78
No nullable reference types
CyrusNajmabadi Jan 14, 2023
f90faaa
Update apis
CyrusNajmabadi Jan 15, 2023
0185eac
Add apis
CyrusNajmabadi Jan 15, 2023
e6a3b1f
Add api
CyrusNajmabadi Jan 15, 2023
bc8ba4d
Add api
CyrusNajmabadi Jan 15, 2023
313b69c
Add api
CyrusNajmabadi Jan 15, 2023
6aeac08
Fix
CyrusNajmabadi Jan 15, 2023
308acb0
NRT
CyrusNajmabadi Jan 15, 2023
288b7c9
NRT
CyrusNajmabadi Jan 15, 2023
0f12baa
NRT
CyrusNajmabadi Jan 15, 2023
6e7cee3
Fix
CyrusNajmabadi Jan 15, 2023
f81f89f
Move
CyrusNajmabadi Jan 15, 2023
2b27982
Add error facts
CyrusNajmabadi Jan 15, 2023
a5e8b9e
Add error facts
CyrusNajmabadi Jan 15, 2023
9bbda42
Add tests
CyrusNajmabadi Jan 15, 2023
2e6998e
Add tests
CyrusNajmabadi Jan 15, 2023
5dddfc2
Add c# 11 test
CyrusNajmabadi Jan 15, 2023
9e2c969
Add unsafe tests
CyrusNajmabadi Jan 15, 2023
492c9ea
Add unsafe tests
CyrusNajmabadi Jan 15, 2023
74cd663
Dynamic work
CyrusNajmabadi Jan 15, 2023
0fae0b0
Update feature status
CyrusNajmabadi Jan 15, 2023
0eb5ee5
Delete
CyrusNajmabadi Jan 15, 2023
e169a14
Update
CyrusNajmabadi Jan 15, 2023
e5e06c4
Add comment
CyrusNajmabadi Jan 15, 2023
b860116
Fix test
CyrusNajmabadi Jan 15, 2023
972e75a
Fix test
CyrusNajmabadi Jan 15, 2023
54374bd
Fix test
CyrusNajmabadi Jan 15, 2023
42d7759
Add tests
CyrusNajmabadi Jan 15, 2023
82254d4
Add tests
CyrusNajmabadi Jan 15, 2023
28c7cff
Update docs/Language Feature Status.md
CyrusNajmabadi Jan 25, 2023
762bd01
Add tests
CyrusNajmabadi Jan 25, 2023
2c4c046
Add support for top level dynamic
CyrusNajmabadi Jan 25, 2023
9bab6d6
Add support for top level dynamic
CyrusNajmabadi Jan 26, 2023
f78bbd7
Fix loc string
CyrusNajmabadi Jan 26, 2023
275a688
Move into 12.0 section
CyrusNajmabadi Jan 27, 2023
5f3a2c4
Add test
CyrusNajmabadi Jan 27, 2023
3a80d86
Add test
CyrusNajmabadi Jan 27, 2023
8dbb1ec
Move errors to binding
CyrusNajmabadi Jan 27, 2023
087b508
Add tests
CyrusNajmabadi Jan 27, 2023
0f25385
Use file scoped namespace
CyrusNajmabadi Jan 27, 2023
73982a7
Allow aliases to nint/nuint.
CyrusNajmabadi Jan 27, 2023
ef40e33
Add tests
CyrusNajmabadi Jan 27, 2023
4979ff0
Add tests
CyrusNajmabadi Jan 27, 2023
3cf2096
Add comment
CyrusNajmabadi Jan 27, 2023
07a27aa
Update test
CyrusNajmabadi Jan 27, 2023
6321355
Merge remote-tracking branch 'upstream/features/UsingAliasesTypes' in…
CyrusNajmabadi Jan 27, 2023
cb49fae
Merge remote-tracking branch 'upstream/features/UsingAliasesTypes' in…
CyrusNajmabadi Jan 30, 2023
8125da5
'dynamic' should bind to type
CyrusNajmabadi Jan 30, 2023
08279fb
Update docs/Language Feature Status.md
CyrusNajmabadi Jan 30, 2023
3b78a6d
Update tests
CyrusNajmabadi Jan 30, 2023
f7593d3
Merge branch 'usingAliasType' of https://github.com/CyrusNajmabadi/ro…
CyrusNajmabadi Jan 30, 2023
50e0ff4
PR feedback
CyrusNajmabadi Jan 31, 2023
3a5efe6
switch to typesymbol
CyrusNajmabadi Jan 31, 2023
149e5b5
Simplify
CyrusNajmabadi Jan 31, 2023
e154966
Add tests
CyrusNajmabadi Jan 31, 2023
73531cf
Add tests
CyrusNajmabadi Jan 31, 2023
fbf9b8d
Merge remote-tracking branch 'upstream/features/UsingAliasesTypes' in…
CyrusNajmabadi Feb 2, 2023
33ebdbe
Named parameter
CyrusNajmabadi Feb 2, 2023
bcbdcd6
Remove unused usings
CyrusNajmabadi Feb 2, 2023
3e1619a
Improve tests
CyrusNajmabadi Feb 2, 2023
8bffc64
Use RegularPreview
CyrusNajmabadi Feb 2, 2023
b114890
Update tests
CyrusNajmabadi Feb 2, 2023
e056e6b
Fix comment
CyrusNajmabadi Feb 2, 2023
6cc95af
Merge tests
CyrusNajmabadi Feb 2, 2023
b5a3ba3
Merge tests
CyrusNajmabadi Feb 2, 2023
c9d5b90
Add tests
CyrusNajmabadi Feb 2, 2023
97161ee
Syntax test only
CyrusNajmabadi Feb 2, 2023
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/Language Feature Status.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ efforts behind them.
| [Lambda default parameters](https://github.com/dotnet/csharplang/issues/6051) | [lambda-default-parameters](https://github.com/dotnet/roslyn/tree/features/lambda-default-parameters) | [Merged into 17.5p2](https://github.com/dotnet/roslyn/issues/62485) | [adamperlin](https://github.com/adamperlin), [jjonescz](https://github.com/jjonescz) | [333fred](https://github.com/333fred), [cston](https://github.com/cston) | [captainsafia](https://github.com/captainsafia) |
| [Default in deconstruction](https://github.com/dotnet/roslyn/pull/25562) | [decon-default](https://github.com/dotnet/roslyn/tree/features/decon-default) | [In Progress](https://github.com/dotnet/roslyn/issues/25559) | [jcouv](https://github.com/jcouv) | [gafter](https://github.com/gafter) | [jcouv](https://github.com/jcouv) |
| [Collection Literals](https://github.com/dotnet/csharplang/issues/5354) | [CollectionLiterals](https://github.com/dotnet/roslyn/tree/features/CollectionLiterals) | | [cston](https://github.com/cston) | [333fred](https://github.com/333fred), [RikkiGibson](https://github.com/RikkiGibson) | [CyrusNajmabadi](https://github.com/CyrusNajmabadi) |
| [Using aliases for any type](https://github.com/dotnet/csharplang/issues/4284) | [UsingAliasTypes](https://github.com/dotnet/roslyn/tree/features/UsingAliasTypes) | [Test Plan](https://github.com/dotnet/roslyn/issues/56323) | [CyrusNajmabadi](https://github.com/CyrusNajmabadi) | [jcouv](https://github.com/jcouv) [cston](https://github.com/cston) | |

# C# 11.0

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -186,8 +186,8 @@ private static async Task<CompilationUnitSyntax> ExpandUsingDirectivesAsync(

private static async Task<SyntaxNode> ExpandUsingDirectiveAsync(Document document, UsingDirectiveSyntax usingDirective, CancellationToken cancellationToken)
{
var newName = await Simplifier.ExpandAsync(usingDirective.Name, document, cancellationToken: cancellationToken).ConfigureAwait(false);
return usingDirective.WithName(newName);
var newType = await Simplifier.ExpandAsync(usingDirective.Type, document, cancellationToken: cancellationToken).ConfigureAwait(false);
return usingDirective.WithType(newType);
}

private static CompilationUnitSyntax MoveUsingsInsideNamespace(CompilationUnitSyntax compilationUnit)
Expand Down
150 changes: 102 additions & 48 deletions src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs
Original file line number Diff line number Diff line change
Expand Up @@ -477,10 +477,19 @@ internal NamespaceOrTypeOrAliasSymbolWithAnnotations BindNamespaceOrTypeOrAliasS
{
// ref needs to be handled by the caller
var refTypeSyntax = (RefTypeSyntax)syntax;
var refToken = refTypeSyntax.RefKeyword;
if (!syntax.HasErrors)
{
diagnostics.Add(ErrorCode.ERR_UnexpectedToken, refToken.GetLocation(), refToken.ToString());
var refToken = refTypeSyntax.RefKeyword;

// Specialized diagnostic if our parent is a using directive.
if (refTypeSyntax.Parent is UsingDirectiveSyntax)
Copy link
Member Author

Choose a reason for hiding this comment

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

this moved from teh parser to here (since there's difficulty representing this in the syntax model). Note: we could just get rid of this specialized error (since we have the more generic one below). But i don't mind keeping this.

{
diagnostics.Add(ErrorCode.ERR_BadRefInUsingAlias, refToken.GetLocation());
}
else
{
diagnostics.Add(ErrorCode.ERR_UnexpectedToken, refToken.GetLocation(), refToken.ToString());
}
}

return BindNamespaceOrTypeOrAliasSymbol(refTypeSyntax.Type, diagnostics, basesBeingResolved, suppressUseSiteDiagnostics);
Expand Down Expand Up @@ -830,29 +839,6 @@ private NamespaceOrTypeOrAliasSymbolWithAnnotations BindSimpleNamespaceOrTypeOrA
}
}

private static bool IsViableType(LookupResult result)
Copy link
Member Author

Choose a reason for hiding this comment

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

moved to be helper local function in the one place it is used.

{
if (!result.IsMultiViable)
{
return false;
}

foreach (var s in result.Symbols)
{
switch (s.Kind)
{
case SymbolKind.Alias:
if (((AliasSymbol)s).Target.Kind == SymbolKind.NamedType) return true;
break;
case SymbolKind.NamedType:
case SymbolKind.TypeParameter:
return true;
}
}

return false;
}

protected NamespaceOrTypeOrAliasSymbolWithAnnotations BindNonGenericSimpleNamespaceOrTypeOrAliasSymbol(
IdentifierNameSyntax node,
BindingDiagnosticBag diagnostics,
Expand All @@ -875,7 +861,7 @@ protected NamespaceOrTypeOrAliasSymbolWithAnnotations BindNonGenericSimpleNamesp
}

var errorResult = CreateErrorIfLookupOnTypeParameter(node.Parent, qualifierOpt, identifierValueText, 0, diagnostics);
if ((object)errorResult != null)
if (errorResult is not null)
{
return TypeWithAnnotations.Create(errorResult);
}
Expand All @@ -891,23 +877,24 @@ protected NamespaceOrTypeOrAliasSymbolWithAnnotations BindNonGenericSimpleNamesp

// If we were looking up "dynamic" or "nint" at the topmost level and didn't find anything good,
// use that particular type (assuming the /langversion is supported).
if ((object)qualifierOpt == null &&
!IsViableType(result))
if (qualifierOpt is null &&
!isViableType(result))
{
if (node.Identifier.ValueText == "dynamic")
{
if ((node.Parent == null ||
node.Parent.Kind() != SyntaxKind.Attribute && // dynamic not allowed as attribute type
SyntaxFacts.IsInTypeOnlyContext(node)) &&
Compilation.LanguageVersion >= MessageID.IDS_FeatureDynamic.RequiredVersion())
if (dynamicAllowed())
{
bindingResult = Compilation.DynamicType;
ReportUseSiteDiagnosticForDynamic(diagnostics, node);
}
}
else
{
bindingResult = BindNativeIntegerSymbolIfAny(node, diagnostics);
// nint/nuint is allowed to bind to an existing namespace.
if (!isViableNamespace(result))
{
bindingResult = BindNativeIntegerSymbolIfAny(node, diagnostics);
}
}
}

Expand All @@ -919,15 +906,80 @@ protected NamespaceOrTypeOrAliasSymbolWithAnnotations BindNonGenericSimpleNamesp
if (bindingResult.Kind == SymbolKind.Alias)
{
var aliasTarget = ((AliasSymbol)bindingResult).GetAliasTarget(basesBeingResolved);
if (aliasTarget.Kind == SymbolKind.NamedType && ((NamedTypeSymbol)aliasTarget).ContainsDynamic())
if (aliasTarget is TypeSymbol type)
{
ReportUseSiteDiagnosticForDynamic(diagnostics, node);
if (type.ContainsDynamic())
{
ReportUseSiteDiagnosticForDynamic(diagnostics, node);
}

if (type.IsUnsafe())
{
ReportUnsafeIfNotAllowed(node, diagnostics);
}
}
}
}

result.Free();
return NamespaceOrTypeOrAliasSymbolWithAnnotations.CreateUnannotated(AreNullableAnnotationsEnabled(node.Identifier), bindingResult);

bool dynamicAllowed()
{
if (Compilation.LanguageVersion < MessageID.IDS_FeatureDynamic.RequiredVersion())
return false;

if (node.Parent == null)
return true;

// dynamic not allowed as attribute type
CyrusNajmabadi marked this conversation as resolved.
Show resolved Hide resolved
if (node.Parent.Kind() == SyntaxKind.Attribute)
return false;

if (SyntaxFacts.IsInTypeOnlyContext(node))
return true;

// using X = dynamic; is legal.
if (node.Parent is UsingDirectiveSyntax { Alias: not null })
return true;

return false;
}

static bool isViableType(LookupResult result)
{
if (!result.IsMultiViable)
return false;

foreach (var s in result.Symbols)
{
switch (s.Kind)
{
case SymbolKind.Alias:
if (((AliasSymbol)s).Target.Kind == SymbolKind.NamedType) return true;
break;
case SymbolKind.NamedType:
case SymbolKind.TypeParameter:
return true;
}
}

return false;
}

static bool isViableNamespace(LookupResult result)
{
if (!result.IsMultiViable)
return false;

foreach (var s in result.Symbols)
{
if (s.Kind == SymbolKind.Namespace)
return true;
}

return false;
}
}

/// <summary>
Expand All @@ -936,24 +988,26 @@ protected NamespaceOrTypeOrAliasSymbolWithAnnotations BindNonGenericSimpleNamesp
/// </summary>
private NamedTypeSymbol BindNativeIntegerSymbolIfAny(IdentifierNameSyntax node, BindingDiagnosticBag diagnostics)
{
SpecialType specialType;
switch (node.Identifier.Text)
{
case "nint":
specialType = SpecialType.System_IntPtr;
break;
case "nuint":
specialType = SpecialType.System_UIntPtr;
break;
default:
CyrusNajmabadi marked this conversation as resolved.
Show resolved Hide resolved
return null;
}
var specialType =
node.IsNint ? SpecialType.System_IntPtr :
node.IsNuint ? SpecialType.System_UIntPtr : SpecialType.None;

if (specialType == SpecialType.None)
return null;

switch (node.Parent)
{
case AttributeSyntax parent when parent.Name == node: // [nint]
return null;
case UsingDirectiveSyntax parent when parent.Name == node: // using nint; using A = nuint;
case UsingDirectiveSyntax usingDirective:
if (usingDirective.Alias != null && usingDirective.Type == node)
{
// legal to write `using A = nuint;` as long as using-alias-to-type is enabled (checked later).
break;
}

// `using nint;` not legal where 'nint' has the System.IntPtr meaning. It is legal if you were to
// have `namespace nint { }` somewhere. That is handled though in our caller.
return null;
case ArgumentSyntax parent when // nameof(nint)
(IsInsideNameof &&
Expand Down
4 changes: 2 additions & 2 deletions src/Compilers/CSharp/Portable/Binder/ImportChain.cs
Original file line number Diff line number Diff line change
Expand Up @@ -113,11 +113,11 @@ public Cci.IImportScope Translate(Emit.PEModuleBuilder moduleBuilder, Diagnostic
var assemblyRef = TryGetAssemblyScope(ns, moduleBuilder, diagnostics);
usedNamespaces.Add(Cci.UsedNamespaceOrType.CreateNamespace(ns.GetCciAdapter(), assemblyRef, alias));
}
else if (!target.ContainingAssembly.IsLinked)
else if (target is TypeSymbol { ContainingAssembly.IsLinked: false } typeSymbol)
{
// We skip alias imports of embedded types to avoid breaking existing code that
// imports types that can't be embedded but doesn't use them anywhere else in the code.
var typeRef = GetTypeReference((TypeSymbol)target, syntax, moduleBuilder, diagnostics);
var typeRef = GetTypeReference(typeSymbol, syntax, moduleBuilder, diagnostics);
usedNamespaces.Add(Cci.UsedNamespaceOrType.CreateType(typeRef, alias));
}
}
Expand Down
12 changes: 12 additions & 0 deletions src/Compilers/CSharp/Portable/CSharpResources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -6847,6 +6847,18 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
<data name="WRN_DoNotCompareFunctionPointers_Title" xml:space="preserve">
<value>Do not compare function pointer values</value>
</data>
<data name="IDS_FeatureUsingTypeAlias" xml:space="preserve">
<value>using type alias</value>
</data>
<data name="ERR_BadRefInUsingAlias" xml:space="preserve">
<value>Using alias cannot be a 'ref' type.</value>
</data>
<data name="ERR_BadUnsafeInUsingDirective" xml:space="preserve">
<value>Only a using alias can be 'unsafe'.</value>
</data>
<data name="ERR_BadNullableReferenceTypeInUsingAlias" xml:space="preserve">
<value>Using alias cannot be a nullable reference type.</value>
</data>
<data name="ERR_FunctionPointerTypesInAttributeNotSupported" xml:space="preserve">
<value>Using a function pointer type in this context is not supported.</value>
</data>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,12 @@ private static QuickAttributes GetQuickAttributes(
continue;
}

result |= QuickAttributeHelpers.GetQuickAttributes(directive.Name.GetUnqualifiedName().Identifier.ValueText, inAttribute: false);
if (directive.Name is not NameSyntax name)
{
continue;
CyrusNajmabadi marked this conversation as resolved.
Show resolved Hide resolved
}

result |= QuickAttributeHelpers.GetQuickAttributes(name.GetUnqualifiedName().Identifier.ValueText, inAttribute: false);
}

return result;
Expand Down
5 changes: 5 additions & 0 deletions src/Compilers/CSharp/Portable/Errors/ErrorCode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2162,6 +2162,11 @@ internal enum ErrorCode
ERR_UnscopedRefAttributeInterfaceImplementation = 9102,
ERR_UnrecognizedRefSafetyRulesAttributeVersion = 9103,
ERR_BadSpecialByRefUsing = 9104,

ERR_BadRefInUsingAlias = 9105,
ERR_BadUnsafeInUsingDirective = 9106,
ERR_BadNullableReferenceTypeInUsingAlias = 9107,

#endregion

// Note: you will need to do the following after adding warnings:
Expand Down
3 changes: 3 additions & 0 deletions src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2279,6 +2279,9 @@ internal static bool IsBuildOnlyDiagnostic(ErrorCode code)
case ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation:
case ErrorCode.ERR_UnrecognizedRefSafetyRulesAttributeVersion:
case ErrorCode.ERR_BadSpecialByRefUsing:
case ErrorCode.ERR_BadRefInUsingAlias:
case ErrorCode.ERR_BadUnsafeInUsingDirective:
case ErrorCode.ERR_BadNullableReferenceTypeInUsingAlias:
return false;
default:
// NOTE: All error codes must be explicitly handled in this switch statement
Expand Down
3 changes: 3 additions & 0 deletions src/Compilers/CSharp/Portable/Errors/MessageID.cs
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,8 @@ internal enum MessageID
IDS_Missing = MessageBase + 12830,
IDS_FeatureLambdaOptionalParameters = MessageBase + 12831,
IDS_FeatureLambdaParamsArray = MessageBase + 12832,

IDS_FeatureUsingTypeAlias = MessageBase + 12833,
}

// Message IDs may refer to strings that need to be localized.
Expand Down Expand Up @@ -388,6 +390,7 @@ internal static LanguageVersion RequiredVersion(this MessageID feature)
// C# preview features.
case MessageID.IDS_FeatureLambdaOptionalParameters: // semantic check
case MessageID.IDS_FeatureLambdaParamsArray: // semantic check
case MessageID.IDS_FeatureUsingTypeAlias: // semantic check
return LanguageVersion.Preview;

// C# 11.0 features.
Expand Down
26 changes: 13 additions & 13 deletions src/Compilers/CSharp/Portable/Generated/CSharp.Generated.g4

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading