Skip to content

Commit

Permalink
Track assemblies declaring well-known types used by a compilation.
Browse files Browse the repository at this point in the history
Related to dotnet#37768.
  • Loading branch information
AlekseyTs committed Nov 25, 2019
1 parent c5bc1e0 commit 297b0ba
Show file tree
Hide file tree
Showing 92 changed files with 1,289 additions and 416 deletions.
2 changes: 1 addition & 1 deletion src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,7 @@ internal bool CheckValueKind(SyntaxNode node, BoundExpression expr, BindValueKin
if (boundAccess.Indices.Length == 1 &&
TypeSymbol.Equals(
boundAccess.Indices[0].Type,
Compilation.GetWellKnownType(WellKnownType.System_Range),
Compilation.GetWellKnownType(WellKnownType.System_Range, recordUsage: false),
TypeCompareKind.ConsiderEverything))
{
// Range indexer is an rvalue
Expand Down
3 changes: 2 additions & 1 deletion src/Compilers/CSharp/Portable/Binder/Binder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -669,6 +669,7 @@ internal bool IsSymbolAccessibleConditional(
internal static void ReportUseSiteDiagnosticForSynthesizedAttribute(
CSharpCompilation compilation,
WellKnownMember attributeMember,
bool recordUsage,
DiagnosticBag diagnostics,
Location location = null,
CSharpSyntaxNode syntax = null)
Expand All @@ -679,7 +680,7 @@ internal static void ReportUseSiteDiagnosticForSynthesizedAttribute(
// (comes from an unified assembly). When the symbol is not found no error is reported. See test VersionUnification_UseSiteDiagnostics_OptionalAttributes.
bool isOptional = WellKnownMembers.IsSynthesizedAttributeOptional(attributeMember);

GetWellKnownTypeMember(compilation, attributeMember, diagnostics, location, syntax, isOptional);
GetWellKnownTypeMember(compilation, attributeMember, recordUsage, diagnostics, location, syntax, isOptional);
}

#if DEBUG
Expand Down
2 changes: 1 addition & 1 deletion src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,7 @@ private BoundExpression CreateStackAllocConversion(SyntaxNode syntax, BoundExpre
break;
case ConversionKind.StackAllocToSpanType:
CheckFeatureAvailability(syntax, MessageID.IDS_FeatureRefStructs, diagnostics);
stackAllocType = Compilation.GetWellKnownType(WellKnownType.System_Span_T).Construct(elementType);
stackAllocType = Compilation.GetWellKnownType(WellKnownType.System_Span_T, recordUsage: false).Construct(elementType);
break;
default:
throw ExceptionUtilities.UnexpectedValue(conversion.Kind);
Expand Down
10 changes: 6 additions & 4 deletions src/Compilers/CSharp/Portable/Binder/Binder_Deconstruct.cs
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ private BoundExpression FixTupleLiteral(ArrayBuilder<DeconstructionVariable> che

// If we already have diagnostics at this point, it is not worth collecting likely duplicate diagnostics from making the merged type
bool hadErrors = diagnostics.HasAnyErrors();
TypeSymbol mergedTupleType = MakeMergedTupleType(checkedVariables, (BoundTupleLiteral)boundRHS, syntax, Compilation, hadErrors ? null : diagnostics);
TypeSymbol mergedTupleType = MakeMergedTupleType(checkedVariables, (BoundTupleLiteral)boundRHS, syntax, hadErrors ? null : diagnostics);
if ((object)mergedTupleType != null)
{
boundRHS = GenerateConversionForAssignment(mergedTupleType, boundRHS, diagnostics);
Expand Down Expand Up @@ -457,7 +457,7 @@ private string GetDebuggerDisplay()
/// For cases where the RHS of a deconstruction-assignment is a tuple literal, the type information from the LHS determines the merged type, since all variables have a type.
/// Returns null if a merged tuple type could not be fabricated.
/// </summary>
private static TypeSymbol MakeMergedTupleType(ArrayBuilder<DeconstructionVariable> lhsVariables, BoundTupleLiteral rhsLiteral, CSharpSyntaxNode syntax, CSharpCompilation compilation, DiagnosticBag diagnostics)
private TypeSymbol MakeMergedTupleType(ArrayBuilder<DeconstructionVariable> lhsVariables, BoundTupleLiteral rhsLiteral, CSharpSyntaxNode syntax, DiagnosticBag diagnostics)
{
int leftLength = lhsVariables.Count;
int rightLength = rhsLiteral.Arguments.Length;
Expand All @@ -477,7 +477,7 @@ private static TypeSymbol MakeMergedTupleType(ArrayBuilder<DeconstructionVariabl
if (element.Kind == BoundKind.TupleLiteral)
{
// (variables) on the left and (elements) on the right
mergedType = MakeMergedTupleType(variable.NestedVariables, (BoundTupleLiteral)element, syntax, compilation, diagnostics);
mergedType = MakeMergedTupleType(variable.NestedVariables, (BoundTupleLiteral)element, syntax, diagnostics);
}
else if ((object)mergedType == null)
{
Expand Down Expand Up @@ -522,10 +522,11 @@ private static TypeSymbol MakeMergedTupleType(ArrayBuilder<DeconstructionVariabl
elementTypesWithAnnotations: typesWithAnnotationsBuilder.ToImmutableAndFree(),
elementLocations: locationsBuilder.ToImmutableAndFree(),
elementNames: default(ImmutableArray<string>),
compilation: compilation,
compilation: Compilation,
diagnostics: diagnostics,
shouldCheckConstraints: true,
includeNullability: false,
recordUsage: !IsSemanticModelBinder,
errorPositions: default(ImmutableArray<bool>),
syntax: syntax);
}
Expand Down Expand Up @@ -572,6 +573,7 @@ private BoundTupleExpression DeconstructionVariablesAsTuple(CSharpSyntaxNode syn
tupleNames, this.Compilation,
shouldCheckConstraints: !ignoreDiagnosticsFromTuple,
includeNullability: false,
recordUsage: !(ignoreDiagnosticsFromTuple || IsSemanticModelBinder),
errorPositions: disallowInferredNames ? inferredPositions : default,
syntax: syntax, diagnostics: ignoreDiagnosticsFromTuple ? null : diagnostics);

Expand Down
37 changes: 20 additions & 17 deletions src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -819,6 +819,7 @@ private BoundExpression BindDeclarationVariablesForErrorRecovery(TypeWithAnnotat
Compilation,
shouldCheckConstraints: false,
includeNullability: false,
recordUsage: false,
errorPositions: disallowInferredNames ? inferredPositions : default);

return new BoundConvertedTupleLiteral(syntax, sourceTuple: null, wasTargetTyped: true, subExpressions, tupleNames, inferredPositions, tupleType);
Expand Down Expand Up @@ -897,11 +898,11 @@ private BoundExpression BindTupleExpression(TupleExpressionSyntax node, Diagnost

tupleTypeOpt = TupleTypeSymbol.Create(node.Location, elements, locations, elementNames,
this.Compilation, syntax: node, diagnostics: diagnostics, shouldCheckConstraints: true,
includeNullability: false, errorPositions: disallowInferredNames ? inferredPositions : default(ImmutableArray<bool>));
includeNullability: false, recordUsage: !IsSemanticModelBinder, errorPositions: disallowInferredNames ? inferredPositions : default(ImmutableArray<bool>));
}
else
{
TupleTypeSymbol.VerifyTupleTypePresent(elements.Length, node, this.Compilation, diagnostics);
TupleTypeSymbol.VerifyTupleTypePresent(elements.Length, node, this.Compilation, recordUsage: !IsSemanticModelBinder, diagnostics);
}

// Always track the inferred positions in the bound node, so that conversions don't produce a warning
Expand Down Expand Up @@ -1100,7 +1101,7 @@ private BoundExpression BindRefType(RefTypeExpressionSyntax node, DiagnosticBag
bool hasErrors = argument.HasAnyErrors;

TypeSymbol typedReferenceType = this.Compilation.GetSpecialType(SpecialType.System_TypedReference);
TypeSymbol typeType = this.Compilation.GetWellKnownType(WellKnownType.System_Type);
TypeSymbol typeType = this.GetWellKnownType(WellKnownType.System_Type, diagnostics, node);
HashSet<DiagnosticInfo> useSiteDiagnostics = null;
Conversion conversion = this.Conversions.ClassifyConversionFromExpression(argument, typedReferenceType, ref useSiteDiagnostics);
diagnostics.Add(node, useSiteDiagnostics);
Expand Down Expand Up @@ -2074,7 +2075,7 @@ private BoundExpression BindFromEndIndexExpression(PrefixUnaryExpressionSyntax n
}

BoundExpression boundConversion = CreateConversion(boundOperand, conversion, intType, diagnostics);
MethodSymbol symbolOpt = GetWellKnownTypeMember(Compilation, WellKnownMember.System_Index__ctor, diagnostics, syntax: node) as MethodSymbol;
MethodSymbol symbolOpt = GetWellKnownTypeMember(WellKnownMember.System_Index__ctor, diagnostics, syntax: node) as MethodSymbol;

return new BoundFromEndIndexExpression(node, boundConversion, symbolOpt, indexType);
}
Expand Down Expand Up @@ -2110,7 +2111,6 @@ private BoundExpression BindRangeExpression(RangeExpressionSyntax node, Diagnost
if (memberOpt is object)
{
symbolOpt = (MethodSymbol)GetWellKnownTypeMember(
Compilation,
memberOpt.GetValueOrDefault(),
diagnostics,
syntax: node,
Expand All @@ -2120,7 +2120,6 @@ private BoundExpression BindRangeExpression(RangeExpressionSyntax node, Diagnost
if (symbolOpt is null)
{
symbolOpt = (MethodSymbol)GetWellKnownTypeMember(
Compilation,
WellKnownMember.System_Range__ctor,
diagnostics,
syntax: node);
Expand Down Expand Up @@ -6136,10 +6135,10 @@ private bool IsWinRTAsyncInterface(TypeSymbol type)

var namedType = ((NamedTypeSymbol)type).ConstructedFrom;
return
TypeSymbol.Equals(namedType, Compilation.GetWellKnownType(WellKnownType.Windows_Foundation_IAsyncAction), TypeCompareKind.ConsiderEverything2) ||
TypeSymbol.Equals(namedType, Compilation.GetWellKnownType(WellKnownType.Windows_Foundation_IAsyncActionWithProgress_T), TypeCompareKind.ConsiderEverything2) ||
TypeSymbol.Equals(namedType, Compilation.GetWellKnownType(WellKnownType.Windows_Foundation_IAsyncOperation_T), TypeCompareKind.ConsiderEverything2) ||
TypeSymbol.Equals(namedType, Compilation.GetWellKnownType(WellKnownType.Windows_Foundation_IAsyncOperationWithProgress_T2), TypeCompareKind.ConsiderEverything2);
TypeSymbol.Equals(namedType, Compilation.GetWellKnownType(WellKnownType.Windows_Foundation_IAsyncAction, recordUsage: false), TypeCompareKind.ConsiderEverything2) ||
TypeSymbol.Equals(namedType, Compilation.GetWellKnownType(WellKnownType.Windows_Foundation_IAsyncActionWithProgress_T, recordUsage: false), TypeCompareKind.ConsiderEverything2) ||
TypeSymbol.Equals(namedType, Compilation.GetWellKnownType(WellKnownType.Windows_Foundation_IAsyncOperation_T, recordUsage: false), TypeCompareKind.ConsiderEverything2) ||
TypeSymbol.Equals(namedType, Compilation.GetWellKnownType(WellKnownType.Windows_Foundation_IAsyncOperationWithProgress_T2, recordUsage: false), TypeCompareKind.ConsiderEverything2);
}

private BoundExpression BindMemberAccessBadResult(BoundMethodGroup node)
Expand Down Expand Up @@ -7070,7 +7069,7 @@ private BoundExpression BindArrayAccess(ExpressionSyntax node, BoundExpression e
TypeSymbol resultType = rank == 1 &&
TypeSymbol.Equals(
convertedArguments[0].Type,
Compilation.GetWellKnownType(WellKnownType.System_Range),
Compilation.GetWellKnownType(WellKnownType.System_Range, recordUsage: false),
TypeCompareKind.ConsiderEverything)
? arrayType
: arrayType.ElementType;
Expand Down Expand Up @@ -7110,7 +7109,6 @@ private BoundExpression ConvertToArrayIndex(BoundExpression index, SyntaxNode no
{
// This member is needed for lowering and should produce an error if not present
_ = GetWellKnownTypeMember(
Compilation,
WellKnownMember.System_Runtime_CompilerServices_RuntimeHelpers__GetSubArray_T,
diagnostics,
syntax: node);
Expand All @@ -7120,7 +7118,6 @@ private BoundExpression ConvertToArrayIndex(BoundExpression index, SyntaxNode no
{
// This member is needed for lowering and should produce an error if not present
_ = GetWellKnownTypeMember(
Compilation,
WellKnownMember.System_Index__GetOffset,
diagnostics,
syntax: node);
Expand All @@ -7146,7 +7143,7 @@ private BoundExpression ConvertToArrayIndex(BoundExpression index, SyntaxNode no
private BoundExpression TryImplicitConversionToArrayIndex(BoundExpression expr, WellKnownType wellKnownType, SyntaxNode node, DiagnosticBag diagnostics)
{
HashSet<DiagnosticInfo> useSiteDiagnostics = null;
TypeSymbol type = GetWellKnownType(wellKnownType, ref useSiteDiagnostics);
TypeSymbol type = GetWellKnownTypeWithoutRecordingUsage(wellKnownType, ref useSiteDiagnostics);

if (type.IsErrorType())
{
Expand All @@ -7157,6 +7154,12 @@ private BoundExpression TryImplicitConversionToArrayIndex(BoundExpression expr,
var result = TryImplicitConversionToArrayIndex(expr, type, node, attemptDiagnostics);
if (result is object)
{
if (!IsSemanticModelBinder)
{
Compilation.AddUsedAssembly(type.ContainingAssembly);
}

diagnostics.Add(node, useSiteDiagnostics);
diagnostics.AddRange(attemptDiagnostics);
}
attemptDiagnostics.Free();
Expand Down Expand Up @@ -7577,10 +7580,10 @@ private bool TryBindIndexOrRangeIndexer(

var argType = arguments[0].Type;
bool argIsIndex = TypeSymbol.Equals(argType,
Compilation.GetWellKnownType(WellKnownType.System_Index),
Compilation.GetWellKnownType(WellKnownType.System_Index, recordUsage: false),
TypeCompareKind.ConsiderEverything);
bool argIsRange = !argIsIndex && TypeSymbol.Equals(argType,
Compilation.GetWellKnownType(WellKnownType.System_Range),
Compilation.GetWellKnownType(WellKnownType.System_Range, recordUsage: false),
TypeCompareKind.ConsiderEverything);

if ((!argIsIndex && !argIsRange) ||
Expand Down Expand Up @@ -7741,7 +7744,7 @@ void checkWellKnown(WellKnownMember member)
// Check required well-known member. They may not be needed
// during lowering, but it's simpler to always require them to prevent
// the user from getting surprising errors when optimizations fail
_ = GetWellKnownTypeMember(Compilation, member, diagnostics, syntax: syntax);
_ = GetWellKnownTypeMember(member, diagnostics, syntax: syntax);
}

bool tryLookupLengthOrCount(string propertyName, out PropertySymbol valid)
Expand Down
12 changes: 6 additions & 6 deletions src/Compilers/CSharp/Portable/Binder/Binder_Lookup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -854,12 +854,12 @@ private void AddWinRTMembers(

private void GetWellKnownWinRTMemberInterfaces(out NamedTypeSymbol idictSymbol, out NamedTypeSymbol iroDictSymbol, out NamedTypeSymbol iListSymbol, out NamedTypeSymbol iCollectionSymbol, out NamedTypeSymbol inccSymbol, out NamedTypeSymbol inpcSymbol)
{
idictSymbol = Compilation.GetWellKnownType(WellKnownType.System_Collections_Generic_IDictionary_KV);
iroDictSymbol = Compilation.GetWellKnownType(WellKnownType.System_Collections_Generic_IReadOnlyDictionary_KV);
iListSymbol = Compilation.GetWellKnownType(WellKnownType.System_Collections_IList);
iCollectionSymbol = Compilation.GetWellKnownType(WellKnownType.System_Collections_ICollection);
inccSymbol = Compilation.GetWellKnownType(WellKnownType.System_Collections_Specialized_INotifyCollectionChanged);
inpcSymbol = Compilation.GetWellKnownType(WellKnownType.System_ComponentModel_INotifyPropertyChanged);
idictSymbol = Compilation.GetWellKnownType(WellKnownType.System_Collections_Generic_IDictionary_KV, recordUsage: false);
iroDictSymbol = Compilation.GetWellKnownType(WellKnownType.System_Collections_Generic_IReadOnlyDictionary_KV, recordUsage: false);
iListSymbol = Compilation.GetWellKnownType(WellKnownType.System_Collections_IList, recordUsage: false);
iCollectionSymbol = Compilation.GetWellKnownType(WellKnownType.System_Collections_ICollection, recordUsage: false);
inccSymbol = Compilation.GetWellKnownType(WellKnownType.System_Collections_Specialized_INotifyCollectionChanged, recordUsage: false);
inpcSymbol = Compilation.GetWellKnownType(WellKnownType.System_ComponentModel_INotifyPropertyChanged, recordUsage: false);
}

private static bool ShouldAddWinRTMembersForInterface(NamedTypeSymbol iface, NamedTypeSymbol idictSymbol, NamedTypeSymbol iroDictSymbol, NamedTypeSymbol iListSymbol, NamedTypeSymbol iCollectionSymbol, NamedTypeSymbol inccSymbol, NamedTypeSymbol inpcSymbol)
Expand Down
11 changes: 8 additions & 3 deletions src/Compilers/CSharp/Portable/Binder/Binder_Patterns.cs
Original file line number Diff line number Diff line change
Expand Up @@ -766,7 +766,7 @@ private bool ShouldUseITuple(
return false;
}

iTupleType = Compilation.GetWellKnownType(WellKnownType.System_Runtime_CompilerServices_ITuple);
iTupleType = Compilation.GetWellKnownType(WellKnownType.System_Runtime_CompilerServices_ITuple, recordUsage: false);
if (iTupleType.TypeKind != TypeKind.Interface)
{
// When compiling to a platform that lacks the interface ITuple (i.e. it is an error type), we simply do not match using it.
Expand All @@ -784,15 +784,20 @@ private bool ShouldUseITuple(
}

// Ensure ITuple has a Length and indexer
iTupleGetLength = (MethodSymbol)Compilation.GetWellKnownTypeMember(WellKnownMember.System_Runtime_CompilerServices_ITuple__get_Length);
iTupleGetItem = (MethodSymbol)Compilation.GetWellKnownTypeMember(WellKnownMember.System_Runtime_CompilerServices_ITuple__get_Item);
iTupleGetLength = (MethodSymbol)Compilation.GetWellKnownTypeMember(WellKnownMember.System_Runtime_CompilerServices_ITuple__get_Length, recordUsage: false);
iTupleGetItem = (MethodSymbol)Compilation.GetWellKnownTypeMember(WellKnownMember.System_Runtime_CompilerServices_ITuple__get_Item, recordUsage: false);
if (iTupleGetLength is null || iTupleGetItem is null)
{
// This might not result in an ideal diagnostic
return false;
}

// passed all the filters; permit using ITuple
if (!IsSemanticModelBinder)
{
Compilation.AddUsedAssembly(iTupleType.ContainingAssembly);
}

return true;

bool hasBaseInterface(TypeSymbol type, NamedTypeSymbol possibleBaseInterface)
Expand Down
Loading

0 comments on commit 297b0ba

Please sign in to comment.