简体   繁体   English

单声道+命名/可选参数=编译器错误?

[英]Mono + named/optional parameters = compiler bug?

I have encountered some unforeseen consequences of porting to mono 2.8.1. 移植到Mono 2.8.1时遇到了一些不可预见的后果。 Problem can be boiled down to a sample program (I have been unable to reduce it further, after cutting several classes and ~1000 lines of code to the file quoted below) 问题可以归结为一个示例程序(在将以下几类和约1000行代码削减到下面引用的文件之后,我无法进一步简化它)

public class Person
{
    public Person(int age, string name = null){}
    public Person(double income, string name = null){}
    public Person(double income, int age, string name = null){}
}

class Program
{
    static void Main()
    {
        Person p = new Person(1.0, name: "John Doe");
    }
}

Compilation of above code with mcs gives output: 上面的代码用mcs编译后输出:

test.cs(22,24): error CS0584: Internal compiler error: Internal error
test.cs(22,20): error CS0266: Cannot implicitly convert type `object' to `NamedParams.Person'. 
An explicit conversion exists (are you missing a cast?)
Compilation failed: 2 error(s), 0 warnings

Removing use of optional/named parameter (ie calling new Person(1.0, null, "John Doe") or new Person(1.0, null, name:"John Doe"), or new Person(1.0, "John Doe") ) leads to flawless compilation. 删除对可选参数/命名参数的使用(例如,调用new Person(1.0,null,“ John Doe”)或new Person(1.0,null,name:“ John Doe”)或new Person(1.0,“ John Doe”))导致完美的编译。 Also, under VS2010 the file (and whole solution with which I started with) compiles fine. 另外,在VS2010下,文件(以及我最初使用的整个解决方案)都可以正常编译。 Casting removes error CS0266, but not CS0584 -- so no surprise there. 投放会删除错误CS0266,但不会删除CS0584-因此,这并不奇怪。

My question: is it me doing something wrong, or mcs (ie bug in mcs is obvious to me -- what else ,,internal error'' would mean, but perhaps it's ok such program won't compile), or maybe Microsoft compiler in VS2010 should not let such code to compile? 我的问题是:是我做错了事还是mcs(即mcs中的错误对我来说很明显-否则,内部错误是什么意思,但也许这样的程序不会编译)还是Microsoft编译器在VS2010中不应该让这样的代码编译吗?

I bet it's mcs who's wrong (unable to guess right constructor), but perhaps it's otherwise and I shouldn't know better? 我敢打赌,是mcs错了(无法猜出正确的构造函数),但是也许是另外一个原因,我不应该知道得更多吗?

PS. PS。 I tried searching for a known bug like this in both Google and Novell's Bugzilla, but was unable to find anything relevant. 我尝试在Google和Novell的Bugzilla中搜索类似的已知错误,但是找不到任何相关的错误。 Again, I may be blind ;) 再次,我可能是盲人;)

Okay, here goes. 好的,去。 The crash is indeed due to the third overload, Person(double income, int age, string name = null) . 崩溃确实是由于第三个重载Person(double income, int age, string name = null)导致的。 The compiler sees you are trying to pass less arguments than what are listed in the signature so it goes looking for optional arguments. 编译器发现您正在尝试传递的参数比签名中列出的参数少,因此它会寻找可选参数。 It happily notices that name is optional and assumes you are not passing that argument. 它很高兴地注意到name是可选的,并假定您没有传递该参数。 It does this by appending a placeholder at the end of the supplied arguments. 它通过在提供的参数的末尾附加一个占位符来做到这一点。 Next, it goes to reorder the named arguments in the list so they end up in their right position. 接下来,它将对列表中的命名参数重新排序,以使它们最终位于正确的位置。 This means John Doe is now correctly at the last position for name , but the placeholder gets into the age position. 这意味着John Doe现在正确位于name的最后一个位置,但是占位符进入了age位置。 The compiler then tries to fill in the default values, but is shocked to find a placeholder at a location which has no default value. 然后,编译器尝试填充默认值,但震惊于在没有默认值的位置找到占位符。 It thinks this can not happen, since the placeholder was only added for an optional argument and now suddenly it is not optional anymore. 它认为不可能发生这种情况,因为仅为可选参数添加了占位符,而现在突然不再使它成为可选参数。 Not knowing what to do, it throws an exception. 不知道该怎么办,它将引发异常。

The following patch seems to fix the issue (however it may break something else, so no warranty): 以下修补程序似乎可以解决此问题(但是它可能会破坏其他功能,因此不提供保修):

--- mono-2.6.7.orig/mcs/mcs/ecore.cs    2009-10-02 12:51:12.000000000 +0200
+++ mono-2.6.7/mcs/mcs/ecore.cs 2010-12-21 02:26:44.000000000 +0100
@@ -3803,6 +3803,15 @@

                                int args_gap = Math.Abs (arg_count - param_count);
                                if (optional_count != 0) {
+                                       // readjust for optional arguments passed as named arguments
+                                       for (int i = 0; i < arguments.Count; i++) {
+                                               NamedArgument na = arguments[i] as NamedArgument;
+                                               if (na == null)
+                                                       continue;
+                                               int index = pd.GetParameterIndexByName (na.Name.Value);
+                                               if (pd.FixedParameters[index].HasDefaultValue)
+                                                       optional_count--;
+                                       }
                                        if (args_gap > optional_count)
                                                return int.MaxValue - 10000 + args_gap - optional_count;

For others coming to this thread. 对于其他来此线程。 The bug is still there in the latest versions of Mono Compiler as of April 2013. I created a work around without needing to modify the compiler using C# overloaded functions. 截至2013年4月,最新版本的Mono编译器中仍然存在该错误。我无需使用C#重载函数就可以修改编译器,从而创建了解决方法。

Foo(int a, bool b = true) {
    Foo(a, b, "Default String");
}

Foo(int a, bool b, string c)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM