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

immutability fixes #958

Merged
merged 9 commits into from
Aug 9, 2024
Merged

immutability fixes #958

merged 9 commits into from
Aug 9, 2024

Conversation

omsmith
Copy link
Contributor

@omsmith omsmith commented Aug 9, 2024

  • require application of all [ConditionallyImmutable.OnlyIf] type paramters
  • a [ConditionallyImmutable] type should not be able to extend/implement an [Immutable] one

Fixes: #956

* require application of all [ConditionallyImmutable.OnlyIf] type
  paramters
* a [ConditionallyImmutable] type should not be able to extend/implement
  an [Immutable] one

Fixes: #956
@omsmith omsmith requested a review from j3parker as a code owner August 9, 2024 14:42
for( int i = 0; i < baseTypeInfo.Type.TypeArguments.Length && !parameterUsed; i++ ) {
ITypeSymbol typeArgument = baseTypeInfo.Type.TypeArguments[ i ];
if( !SymbolEqualityComparer.Default.Equals( typeParameter, typeArgument ) ) {
continue;
Copy link
Member

@j3parker j3parker Aug 9, 2024

Choose a reason for hiding this comment

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

So this would emit a diagnostic for IMyReadOnlyDictionary right?

[ConditionallyImmutable]
class MyKeyValuePair<
  [ConditionallyImmutable.OnlyIf]TKey,
  [ConditionallyImmutable.OnlyIf]TValue
> {}

[ConditionallyImmutable]
interface IMyReadOnlyCollection<
  [ConditionallyImmutable.OnlyIf]T
> {}

[ConditionallyImmutable]
interface IMyReadOnlyDictionary<
  [ConditionallyImmutable.OnlyIf]TKey,
  [ConditionallyImmutable.OnlyIf]TValue
> : IMyReadOnlyCollection<KeyValuePair<TKey, TValue>> {}

because TKey "isn't used" in the type arguments to IMyReadOnlyCollection, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, it would

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You thinking a recursive search?

Copy link
Member

@j3parker j3parker Aug 9, 2024

Choose a reason for hiding this comment

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

Ok -- you agree that the above is safe/we would like it to be accepted in an ideal world, right?

Not saying its a problem with this PR, just wrapping my head around the issue

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ok -- you agree that the above is safe/we would like it to be accepted right?

Yep

Copy link
Member

Choose a reason for hiding this comment

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

You thinking a recursive search?

Something like that but I think it's a maybe a little fancy.

I think what we want to know is, are we (IMyReadOnlyDictionary) "at least" as immutable as all of the interfaces (base class) we implement (derive from)? "At least" meaning that any time the broader type gets judged as immutable we also do...

I think the reason its safe here is IMyReadOnlyCollection<T> is only immutable when T is, ok so recursively we need to care about when KeyValuePair<TKey, TValue> is... again recursively we look at that and see we have conditionals on TKey and TValue....

If we accumulate all those conditionals then I think we want to say OK, are the set of conditionals from my equal to (or a superset of?) the conditionals from my type parameters?

I'm not quite sure though, still thinking about it.

@omsmith
Copy link
Contributor Author

omsmith commented Aug 9, 2024

Hmm, something is broken
image

Comment on lines 118 to 129
for( int i = 0; i < baseTypeInfo.Type.TypeArguments.Length && !parameterUsed; i++ ) {
ITypeSymbol typeArgument = baseTypeInfo.Type.TypeArguments[ i ];
if( !SymbolEqualityComparer.Default.Equals( typeParameter, typeArgument ) ) {
continue;
}

ITypeParameterSymbol baseTypeParameter = baseTypeInfo.Type.TypeParameters[ i ];
if( baseTypeInfo.ConditionalTypeParameters.Contains( baseTypeParameter, SymbolEqualityComparer.Default ) ) {
parameterUsed = true;
break;
}
}
Copy link
Member

Choose a reason for hiding this comment

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

We talked on Zoom about how this chunk could be a helper and that helper would change if we implemented the more powerful logic here (recursive/whatever)

j3parker
j3parker previously approved these changes Aug 9, 2024
Copy link
Member

@j3parker j3parker left a comment

Choose a reason for hiding this comment

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

We talked on zoom about reorganizing this a bit (to cut down on state/nesting) but didn't get anywhere fantastic
EDIT: we're looking at a big tuple switch and that looks promising; if it pans out this approval still stands

baseTypeInfo.Type.GetFullTypeName()
)
);
return;
Copy link
Member

Choose a reason for hiding this comment

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

We talked about how we could drop this return if the diagnostic was on typeParameter instead, like we could emit multiple diagnostics instead. I dno, consider it since this is a new diagnostic anyway

@omsmith omsmith merged commit bc72a4e into main Aug 9, 2024
1 check passed
@omsmith omsmith deleted the omsmith/onlyif branch August 9, 2024 19:48
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.

[ConditionallyImmutable] is unsound
2 participants