godotengine / godot

Godot Engine – Multi-platform 2D and 3D game engine
https://godotengine.org
MIT License
90.27k stars 21.04k forks source link

When using where: struct generic type constraint in C#, build fails with Parse error #33503

Closed JoshLee0915 closed 4 years ago

JoshLee0915 commented 4 years ago

Godot version: 3.1.1 Mono Official

OS/device including version: Windows 10

Issue description: When using where: struct as a generic type constraint if you try to build the project it fails silently with a Parse error in csharp_project. Looks related to issues #23884 and #23545

image

Steps to reproduce:

  1. Create a new C# godot project
  2. Create a C# script with a generic method or generic class with the type constraint of struct
  3. Try to run or build the project in godot

Minimal reproduction project: ParseErrorExampleProject.zip

aaronfranke commented 4 years ago

This is invalid C# code and will not work anywhere, you have a typo. Replace where: struct with where T : struct.

public static void TestMethod<T>(T arg) where T : struct {}

However, it seems that the code still fails with the typo fixed:

modules/mono/mono_gd/gd_mono_utils.cpp:604 - System.Exception: Failed to determine namespace and class for script: res://GenericTest.cs. Parse error: ParseError
editor/editor_node.cpp:5155 - An EditorPlugin build callback failed.
modules/mono/mono_gd/gd_mono_utils.cpp:604 - System.Exception: Failed to determine namespace and class for script: res://GenericTest.cs. Parse error: ParseError

VS Code's syntax highlighting marks this as valid code, and the C# docs agree. It doesn't seem to matter whether this is on a Node-derived script or a System.Object-derived one, it always fails. Also, it only happens with where T : struct, not T : class, and not T : Node, @neikeq

JoshLee0915 commented 4 years ago

Shoot, sorry about that. I threw that example project together really quick and should have double checked the code instead of just looking if it generated the same or similar parser error. I updated the example project to fix the typo.

Spartan322 commented 4 years ago

This is still problem in the 3.2 beta

mysticfall commented 4 years ago

I'm also having a similar problem with one of my files that defines a generic class in a nested namespace:

using EnsureThat;
using Godot;
using JetBrains.Annotations;
using Microsoft.Extensions.Logging;

namespace AlleyCat.Morph
{
    // ReSharper disable ConvertToAutoProperty
    public abstract class MorphDefinition : Resource, IMorphDefinition
    {
        public string Key => ResourceName;

        public string DisplayName => Tr(_displayName);

        public bool Hidden => _hidden;

        [Export, UsedImplicitly] private string _displayName;

        [Export, UsedImplicitly] private bool _hidden;

        protected MorphDefinition(string key, string displayName, bool hidden)
        {
            Ensure.That(key, nameof(key)).IsNotNullOrEmpty();
            Ensure.That(displayName, nameof(displayName)).IsNotNullOrEmpty();

            ResourceName = key;

            _displayName = displayName;
            _hidden = hidden;
        }

        protected MorphDefinition()
        {
        }

        public abstract IMorph CreateMorph(IMorphable morphable, ILoggerFactory loggerFactory);
    }

    namespace Generic
    {
        public abstract class MorphDefinition<T> : MorphDefinition
        {
            public T Default => _default;

            [Export, UsedImplicitly] private T _default;

            protected MorphDefinition(string key, string displayName, T defaultValue, bool hidden) :
                base(key, displayName, hidden)
            {
                _default = defaultValue;
            }

            protected MorphDefinition()
            {
            }
        }
    }
}

What I found to be interesting was, when I change name of the source file to include a space at the end like MorphDefinition .cs, it no longer throws an error and the project builds normally.

I suppose this could mean Godot just ignores such files but it's a no problem in my case since it's just an abstract class so doesn't need to be referenced directly within the editor.