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

Omsmith/conditional parameters fix #668

Merged
merged 3 commits into from
Dec 1, 2020

Conversation

omsmith
Copy link
Contributor

@omsmith omsmith commented Nov 30, 2020

No description provided.

@@ -116,6 +116,10 @@ INamedTypeSymbol typeSymbol
return;
}

if( Attributes.Objects.ConditionallyImmutable.IsDefined( typeSymbol ) ) {
immutabilityContext = immutabilityContext.WithConditionalTypeParametersAsImmutable( typeSymbol );
Copy link
Contributor Author

@omsmith omsmith Nov 30, 2020

Choose a reason for hiding this comment

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

Might be some problem here with say...

[ConditionallyImmutable]
public sealed class Foo<[ConditionallyImmutable.OnlyIf] T> {

  [ConditionallyImmutable]
  public sealed class Bar<[ConditionallyImmutable.OnlyIf] U> {
    // something in here....
  }
}

But I haven't thought about that much.

Copy link
Member

Choose a reason for hiding this comment

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

Open an issue to add test cases?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

/// <summary>
/// This function is intended to provide a new immutability context that considers the conditional type parameters
/// of the ConditionallyImmutable type being checked as immutable. It is important this is only used in those cases,
/// and not for instance while validating type arguments to an [Immutable] type parameter.
Copy link
Contributor Author

@omsmith omsmith Nov 30, 2020

Choose a reason for hiding this comment

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

Not used for the linked function, which keeps conditional type parameters from being passed to strictly immutable ones as arguments.

private static void AnalyzeGenericMethodTypeArguments(
SyntaxNodeAnalysisContext ctx,
ImmutabilityContext immutabilityContext,
GenericNameSyntax syntax
) {
if( syntax.IsFromDocComment() ) {
// ignore things in doccomments such as crefs
return;
}
SymbolInfo info = ctx.SemanticModel.GetSymbolInfo( syntax, ctx.CancellationToken );
var (typeParameters, typeArguments) = GetTypeParamsAndArgs( info.Symbol );
int i = 0;
var paramArgPairs = typeParameters.Zip( typeArguments, ( p, a ) => (p, a, i++) );
foreach( var (parameter, argument, position) in paramArgPairs ) {
// TODO: this should eventually use information from ImmutableTypeInfo
// however the current information about immutable type parameters
// includes [Immutable] filling for what will instead be the upcoming
// [OnlyIf] (e.g. it would be broken for IEnumerable<>)
if( !Attributes.Objects.Immutable.IsDefined( parameter ) ) {
continue;
}
if( !immutabilityContext.IsImmutable(
type: argument,
kind: ImmutableTypeKind.Total,
getLocation: () => syntax.TypeArgumentList.Arguments[position].GetLocation(),
out Diagnostic diagnostic
) ) {
// TODO: not necessarily a good diagnostic for this use-case
ctx.ReportDiagnostic( diagnostic );
}
}
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It would be "nice" if this wasn't sound only because of two different parts of analysis covering for each other, but this is pretty straight forward and doesn't require a concept like "Conditional" vs "Definite" immutability

@@ -17,6 +17,7 @@ namespace D2L.CodeStyle.Analyzers.Immutability {
/// </summary>
internal sealed partial class ImmutabilityContext {
private readonly ImmutableDictionary<INamedTypeSymbol, ImmutableTypeInfo> m_extraImmutableTypes;
private readonly ImmutableHashSet<ITypeParameterSymbol> m_conditionalTypeParameters;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Could just be ITypeSymbol and not parameter specific,, but 🤷 can be adjusted later if needed.

@@ -769,17 +769,17 @@ public sealed class AnalyzedImmutableGenericClassGivenT<[ConditionallyImmutable.



static T /* MemberIsNotReadOnly(Field, m_field, AnalyzedImmutableGenericClassGivenT) */ m_field /**/;
static readonly T m_field;
static /* TypeParameterIsNotKnownToBeImmutable(T) */ T /**/ /* MemberIsNotReadOnly(Field, m_field, AnalyzedImmutableGenericClassGivenT) */ m_field /**/;
Copy link
Contributor Author

@omsmith omsmith Nov 30, 2020

Choose a reason for hiding this comment

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

The conditional parameters aren't added as immutable when verifying statics. They aren't safe to hold as static, only definitely immutable things are.

Copy link
Contributor Author

@omsmith omsmith Nov 30, 2020

Choose a reason for hiding this comment

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

Note that these updates are in the context of

	[ConditionallyImmutable]
	public sealed class AnalyzedImmutableGenericClassGivenT<[ConditionallyImmutable.OnlyIf] T, U> {

Comment on lines -875 to +876
static /* TypeParameterIsNotKnownToBeImmutable(U) */ Types.SomeImmutableGenericInterfaceGivenTU<T, U> /**/ /* MemberIsNotReadOnly(Field, m_field, AnalyzedImmutableGenericClassGivenT) */ m_field /**/;
static readonly /* TypeParameterIsNotKnownToBeImmutable(U) */ Types.SomeImmutableGenericInterfaceGivenTU<T, U> /**/ m_field;
static /* TypeParameterIsNotKnownToBeImmutable(T) */ Types.SomeImmutableGenericInterfaceGivenTU<T, U> /**/ /* MemberIsNotReadOnly(Field, m_field, AnalyzedImmutableGenericClassGivenT) */ m_field /**/;
static readonly /* TypeParameterIsNotKnownToBeImmutable(T) */ Types.SomeImmutableGenericInterfaceGivenTU<T, U> /**/ m_field;
Copy link
Contributor Author

@omsmith omsmith Nov 30, 2020

Choose a reason for hiding this comment

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

I expected this to be TypeParameterIsNotKnownToBeImmutable(T), TypeParameterIsNotKnownToBeImmutable(U), but these diagnostics come from immutableTypeInfo.IsImmutableDefinition, and the result and diagnostic come from the first parameter that's an issue (i.e. it's out Diagnostic, not out IEnumerable<Diagnostic>)

readonly Types.SomeImmutableGenericInterfaceRestrictingT<T, U> m_field;
Types.SomeImmutableGenericInterfaceRestrictingT<T, U> Property { get; }
Types.SomeImmutableGenericInterfaceRestrictingT<T, U> Property { get { return default; } }
static Types.SomeImmutableGenericInterfaceRestrictingT</* TypeParameterIsNotKnownToBeImmutable(T) */ T /**/, U> /* MemberIsNotReadOnly(Field, m_field, AnalyzedImmutableGenericClassGivenT) */ m_field /**/;
Copy link
Contributor Author

@omsmith omsmith Nov 30, 2020

Choose a reason for hiding this comment

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

conditional type parameters aren't considered immutable when checking arguments to immutable type parameters (<[Immutable] T>). These parameters are expecting definitely immutable things.

@omsmith
Copy link
Contributor Author

omsmith commented Nov 30, 2020

It may be a little confusing to be told "T" isn't considered immutable for a static, for instance, but not for trying to hold it directly, but... we'll see how it plays out and address via #650

@omsmith
Copy link
Contributor Author

omsmith commented Nov 30, 2020

Done commenting

Co-authored-by: Jacob Parker <jacob@solidangle.ca>
@omsmith omsmith merged commit 954ef6d into master Dec 1, 2020
@omsmith omsmith deleted the omsmith/conditional-parameters-fix branch December 1, 2020 18:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants