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

The type parameter 'TQueryType' cannot be used with the 'as' operator because it does not have a class type constraint nor a 'class' constraint #2396

Closed
marwie opened this issue May 5, 2021 · 4 comments
Labels
Bug Decompiler The decompiler engine itself

Comments

@marwie
Copy link
Contributor

marwie commented May 5, 2021

Input code

Please see #2389

Relevant section in official CSReference
https://github.com/Unity-Technologies/UnityCsReference/blob/61f92bd79ae862c4465d35270f9d1d57befd1761/Modules/Subsystems/SubsystemManager.cs#L35

Erroneous output

<UnityEngine>\UnityEngine\SubsystemManager.cs:3536 The type parameter 'TQueryType' cannot be used with the 'as' operator because it does not have a class type constraint nor a 'class' constraint

private static void AddSubsystemSubset<TBaseTypeInList, TQueryType>(List<TBaseTypeInList> copyFrom, List<TQueryType> copyTo) where TBaseTypeInList : ISubsystem where TQueryType : ISubsystem
{
	TQueryType item = default(TQueryType);
	foreach (TBaseTypeInList item2 in copyFrom)
	{
		int num;
		if (item2 is TQueryType)
		{
			object obj = item2;
			item = (TQueryType)(obj as TQueryType);
			num = 1;
		}
		else
		{
			num = 0;
		}
		if (num != 0)
		{
			copyTo.Add(item);
		}
	}
}

image

Same issue for AddDescriptorSubset https://github.com/Unity-Technologies/UnityCsReference/blob/61f92bd79ae862c4465d35270f9d1d57befd1761/Modules/Subsystems/SubsystemDescriptorStore.cs#L29

image

Details

Please see #2389

@marwie marwie added Bug Decompiler The decompiler engine itself labels May 5, 2021
@dgrunwald
Copy link
Member

The IL code is weird here.
It uses this sequence for the actual cast:

			IL_0021: ldloc.1
			IL_0022: box !!TBaseTypeInList
			IL_0027: isinst !!TQueryType
			IL_002c: unbox.any !!TQueryType
			IL_0031: stloc.2

The isinst in there seems to be completely redundant given that item2 is TQueryType was already checked by the if-condition above.
But ILSpy is translating this snippet locally, so it doesn't know that the type is guaranteed to match.
And if the type does not match, the weird isinst changes the semantics: instead of the InvalidCastException that you'd typically get, you would get a NullReferenceException because the isinst replaces non-matching types with a null reference.

So I don't think we can easily fix this :(

@dgrunwald
Copy link
Member

dgrunwald commented May 7, 2021

I can reproduce the weird IL sequence with:

        public void Generic<T1, T2>(T1 x) where T2 : IDisposable
        {
            if (x is T2 y)
            {
                y.Dispose();
            }
        }

I think we would first need to implement support for pattern matching, as it's only in the context of the whole pattern that we could detect that the second isinst is redundant.

@dgrunwald
Copy link
Member

dgrunwald commented May 7, 2021

Actually we had this topic before for non-generic types: #1903
There we came up with a workaround:
item = (TQueryType)(obj as TQueryType);
can be expressed as
item = (TQueryType)(obj is TQueryType ? obj : null);

Not sure why the workaround doesn't trigger for generic types, but that might be easy to fix.

@marwie
Copy link
Contributor Author

marwie commented May 7, 2021

Oh nice, thanks for the info and fix. I'll try the next few days again!

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Aug 6, 2021
ElektroKill added a commit to dnSpyEx/ILSpy that referenced this issue Aug 11, 2021
…strained generic types.

The logic in the `FixLoneIsInst` transform already handled this correctly, it's just the check in the `isinst` translation that handled the `IsReferenceType == null` case incorrectly.
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Bug Decompiler The decompiler engine itself
Projects
None yet
Development

No branches or pull requests

2 participants