--- /dev/null
+// CS0426: The nested type `WriteLINE' does not exist in the type `System.Console'
+// Line: 10
+
+using System;
+
+public class Test
+{
+ public static void Main ()
+ {
+ var x = nameof (Console.WriteLINE);
+ }
+}
--- /dev/null
+// CS1001: Identifier expected
+// Line: 8
+
+class X
+{
+ public static void Main ()
+ {
+ var r = nameof (List<int2>);
+ }
+}
\ No newline at end of file
--- /dev/null
+// CS1644: Feature `nameof operator' cannot be used because it is not part of the C# 5.0 language specification
+// Line: 10
+// Compiler options: -langversion:5
+
+class C
+{
+ static void Main ()
+ {
+ var n = nameof (Main);
+ }
+}
\ No newline at end of file
--- /dev/null
+// CS8071: Type arguments are not allowed in the nameof operator
+// Line: 10
+
+using SCGL = System.Collections.Generic.List<int>;
+
+class X
+{
+ public static int Main ()
+ {
+ var x = nameof (SCGL.Contains);
+ return 0;
+ }
+}
\ No newline at end of file
--- /dev/null
+// CS8071: Type arguments are not allowed in the nameof operator
+// Line: 16
+
+class G<T>
+{
+ class N
+ {
+ public int Foo;
+ }
+}
+
+class Test
+{
+ public static void Main ()
+ {
+ var n = nameof (G<int>.N.Foo);
+ }
+}
}
public class StringConstant : Constant {
- public readonly string Value;
-
public StringConstant (BuiltinTypes types, string s, Location loc)
: this (types.String, s, loc)
{
Value = s;
}
+ protected StringConstant (Location loc)
+ : base (loc)
+ {
+ }
+
+ public string Value { get; protected set; }
+
public override object GetValue ()
{
return Value;
}
}
+ class NameOf : StringConstant
+ {
+ readonly SimpleName name;
+
+ public NameOf (SimpleName name)
+ : base (name.Location)
+ {
+ this.name = name;
+ }
+
+ protected override Expression DoResolve (ResolveContext rc)
+ {
+ throw new NotSupportedException ();
+ }
+
+ bool ResolveArgumentExpression (ResolveContext rc, Expression expr)
+ {
+ var sn = expr as SimpleName;
+ if (sn != null) {
+ Value = sn.Name;
+
+ if (rc.Module.Compiler.Settings.Version < LanguageVersion.V_6)
+ rc.Report.FeatureIsNotAvailable (rc.Module.Compiler, Location, "nameof operator");
+
+ if (sn.HasTypeArguments) {
+ // TODO: csc compatible but unhelpful error message
+ rc.Report.Error (1001, loc, "Identifier expected");
+ return true;
+ }
+
+ sn.LookupNameExpression (rc, MemberLookupRestrictions.IgnoreArity | MemberLookupRestrictions.IgnoreAmbiguity);
+ return true;
+ }
+
+ var ma = expr as MemberAccess;
+ if (ma != null) {
+ FullNamedExpression fne = ma.LeftExpression as ATypeNameExpression;
+ if (fne == null) {
+ var qam = ma as QualifiedAliasMember;
+ if (qam == null)
+ return false;
+
+ fne = qam.CreateExpressionFromAlias (rc);
+ if (fne == null)
+ return true;
+ }
+
+ Value = ma.Name;
+
+ if (rc.Module.Compiler.Settings.Version < LanguageVersion.V_6)
+ rc.Report.FeatureIsNotAvailable (rc.Module.Compiler, Location, "nameof operator");
+
+ if (ma.HasTypeArguments) {
+ // TODO: csc compatible but unhelpful error message
+ rc.Report.Error (1001, loc, "Identifier expected");
+ return true;
+ }
+
+ var left = fne.ResolveAsTypeOrNamespace (rc);
+ if (left == null)
+ return true;
+
+ var ns = left as NamespaceExpression;
+ if (ns != null) {
+ FullNamedExpression retval = ns.LookupTypeOrNamespace (rc, ma.Name, 0, LookupMode.NameOf, loc);
+ if (retval == null)
+ ns.Error_NamespaceDoesNotExist (rc, ma.Name, 0);
+
+ return true;
+ }
+
+ if (left.Type.IsGenericOrParentIsGeneric) {
+ rc.Report.Error (8071, loc, "Type arguments are not allowed in the nameof operator");
+ }
+
+ var mexpr = MemberLookup (rc, false, left.Type, ma.Name, 0, MemberLookupRestrictions.IgnoreArity | MemberLookupRestrictions.IgnoreAmbiguity, loc);
+ if (mexpr == null) {
+ ma.Error_IdentifierNotFound (rc, left.Type);
+ return true;
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+
+ public Expression ResolveOverload (ResolveContext rc, Arguments args)
+ {
+ if (args == null || args.Count != 1) {
+ name.Error_NameDoesNotExist (rc);
+ return null;
+ }
+
+ var arg = args [0];
+ var res = ResolveArgumentExpression (rc, arg.Expr);
+ if (!res) {
+ name.Error_NameDoesNotExist (rc);
+ return null;
+ }
+
+ type = rc.BuiltinTypes.String;
+ eclass = ExprClass.Value;
+ return this;
+ }
+ }
+
//
// Null constant can have its own type, think of `default (Foo)'
//
{
Normal = 0,
Probing = 1,
- IgnoreAccessibility = 2
+ IgnoreAccessibility = 2,
+ NameOf = 3
}
//
None = 0,
InvocableOnly = 1,
ExactArity = 1 << 2,
- ReadAccess = 1 << 3
+ ReadAccess = 1 << 3,
+ EmptyArguments = 1 << 4,
+ IgnoreArity = 1 << 5,
+ IgnoreAmbiguity = 1 << 6
}
//
}
if (non_method != null) {
- if (ambig_non_method != null && rc != null) {
+ if (ambig_non_method != null && rc != null && (restrictions & MemberLookupRestrictions.IgnoreAmbiguity) == 0) {
var report = rc.Module.Compiler.Report;
report.SymbolRelatedToPreviousError (non_method);
report.SymbolRelatedToPreviousError (ambig_non_method);
return SimpleNameResolve (ec, right_side);
}
+ public void Error_NameDoesNotExist (ResolveContext rc)
+ {
+ rc.Report.Error (103, loc, "The name `{0}' does not exist in the current context", Name);
+ }
+
protected virtual void Error_TypeOrNamespaceNotFound (IMemberContext ctx)
{
if (ctx.CurrentType != null) {
return mg;
}
+ if (Name == "nameof")
+ return new NameOf (this);
+
if (errorMode) {
if (variable_found) {
rc.Report.Error (841, loc, "A local variable `{0}' cannot be used before it is declared", Name);
e = rc.LookupNamespaceOrType (Name, -System.Math.Max (1, Arity), LookupMode.Probing, loc);
if (e != null) {
- if (e.Type.Arity != Arity) {
+ if (e.Type.Arity != Arity && (restrictions & MemberLookupRestrictions.IgnoreArity) == 0) {
Error_TypeArgumentsCannotBeUsed (rc, e.Type, loc);
return e;
}
}
}
- rc.Report.Error (103, loc, "The name `{0}' does not exist in the current context", Name);
+ Error_NameDoesNotExist (rc);
}
return ErrorExpression.Instance;
var atn = expr as ATypeNameExpression;
if (atn != null) {
member_expr = atn.LookupNameExpression (ec, MemberLookupRestrictions.InvocableOnly | MemberLookupRestrictions.ReadAccess);
- if (member_expr != null)
+ if (member_expr != null) {
+ var name_of = member_expr as NameOf;
+ if (name_of != null) {
+ return name_of.ResolveOverload (ec, arguments);
+ }
+
member_expr = member_expr.Resolve (ec);
+ }
} else {
member_expr = expr.Resolve (ec);
}
}
}
- public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext ec)
+ public FullNamedExpression CreateExpressionFromAlias (IMemberContext mc)
{
- if (alias == GlobalAlias) {
- expr = new NamespaceExpression (ec.Module.GlobalRootNamespace, loc);
- return base.ResolveAsTypeOrNamespace (ec);
- }
+ if (alias == GlobalAlias)
+ return new NamespaceExpression (mc.Module.GlobalRootNamespace, loc);
- int errors = ec.Module.Compiler.Report.Errors;
- expr = ec.LookupNamespaceAlias (alias);
+ int errors = mc.Module.Compiler.Report.Errors;
+ var expr = mc.LookupNamespaceAlias (alias);
if (expr == null) {
- if (errors == ec.Module.Compiler.Report.Errors)
- ec.Module.Compiler.Report.Error (432, loc, "Alias `{0}' not found", alias);
+ if (errors == mc.Module.Compiler.Report.Errors)
+ mc.Module.Compiler.Report.Error (432, loc, "Alias `{0}' not found", alias);
+
return null;
}
-
- return base.ResolveAsTypeOrNamespace (ec);
+
+ return expr;
+ }
+
+ public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext mc)
+ {
+ expr = CreateExpressionFromAlias (mc);
+ if (expr == null)
+ return null;
+
+ return base.ResolveAsTypeOrNamespace (mc);
}
protected override Expression DoResolve (ResolveContext ec)
nested = MemberCache.FindNestedType (expr_type, Name, Arity);
if (nested == null) {
if (expr_type == tnew_expr) {
- Error_IdentifierNotFound (rc, expr_type, Name);
+ Error_IdentifierNotFound (rc, expr_type);
return null;
}
return texpr;
}
- protected virtual void Error_IdentifierNotFound (IMemberContext rc, TypeSpec expr_type, string identifier)
+ public void Error_IdentifierNotFound (IMemberContext rc, TypeSpec expr_type)
{
var nested = MemberCache.FindNestedType (expr_type, Name, -System.Math.Max (1, Arity));
return null;
foreach (var ts in found) {
- if (ts.Arity == arity) {
+ if (ts.Arity == arity || mode == LookupMode.NameOf) {
if (best == null) {
if ((ts.Modifiers & Modifiers.INTERNAL) != 0 && !ts.MemberDefinition.IsInternalAsPublic (ctx.Module.DeclaringAssembly) && mode != LookupMode.IgnoreAccessibility)
continue;
--- /dev/null
+class X
+{
+ public static int Main ()
+ {
+ const string s = nameof (X);
+ System.Console.WriteLine (s);
+ if (s != "X")
+ return 1;
+
+ return 0;
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Collections.Generic;
+using SCG = System.Collections.Generic;
+//using SCGL = System.Collections.Generic.List<>;
+
+class A<T>
+{
+ public class B
+ {
+ public int Foo;
+ }
+}
+
+class X
+{
+ bool field;
+ long Prop { get; set; }
+ event Action ev;
+
+ public static int Main ()
+ {
+ int res;
+ var x = new X ();
+ res = x.SimpleName (1);
+ if (res != 0)
+ return res;
+
+ res = x.MemberAccess ();
+ if (res != 0)
+ return 20 + res;
+
+ res = x.QualifiedName ();
+ if (res != 0)
+ return 40 + res;
+
+ return 0;
+ }
+
+ static void GenMethod<T, U, V> ()
+ {
+ }
+
+ int SimpleName<T> (T arg)
+ {
+ const object c = null;
+ decimal d = 0;
+
+ if (nameof (T) != "T")
+ return 1;
+
+ if (nameof (arg) != "arg")
+ return 2;
+
+ if (nameof (c) != "c")
+ return 3;
+
+ if (nameof (d) != "d")
+ return 4;
+
+ if (nameof (field) != "field")
+ return 5;
+
+ if (nameof (Prop) != "Prop")
+ return 6;
+
+ if (nameof (@Main) != "Main")
+ return 7;
+
+ if (nameof (ev) != "ev")
+ return 8;
+
+ if (nameof (Int32) != "Int32")
+ return 9;
+
+ if (nameof (Action) != "Action")
+ return 10;
+
+ if (nameof (List) != "List")
+ return 11;
+
+ if (nameof (GenMethod) != "GenMethod")
+ return 12;
+
+ return 0;
+ }
+
+ int MemberAccess ()
+ {
+ if (nameof (X.field) != "field")
+ return 1;
+
+ if (nameof (X.Prop) != "Prop")
+ return 2;
+
+ if (nameof (Console.WriteLine) != "WriteLine")
+ return 3;
+
+ if (nameof (System.Collections.Generic.List) != "List")
+ return 4;
+
+ if (nameof (System.Collections) != "Collections")
+ return 5;
+
+ if (nameof (X.GenMethod) != "GenMethod")
+ return 6;
+
+// A<>.B bb;
+// if (nameof (A<>.B.Foo) != "B")
+// return 7;
+
+ return 0;
+ }
+
+ int QualifiedName ()
+ {
+ if (nameof (global::System.Int32) != "Int32")
+ return 1;
+
+ if (nameof (SCG.List) != "List")
+ return 2;
+
+// if (nameof (SCGL.Contains) != "Contains")
+// return 3;
+
+ return 0;
+ }
+}
\ No newline at end of file
--- /dev/null
+using T2;
+
+static class T2
+{
+ public static int nameof (string s)
+ {
+ return 2;
+ }
+}
+
+class X
+{
+ public static int Main ()
+ {
+ string s = "";
+ var v = nameof (s);
+ if (v != 2)
+ return 1;
+
+ return 0;
+ }
+}
\ No newline at end of file
--- /dev/null
+interface IA
+{
+ void M (int arg);
+ int Prop { get; set; }
+}
+
+interface IB
+{
+ void M (string arg);
+ void M<T> (T arg);
+ int Prop { get; set; }
+}
+
+interface I : IA, IB
+{
+ void Extra (string method = nameof (M), string prop = nameof (Prop));
+}
+
+class Ambiguous
+{
+ public static int Main ()
+ {
+ string res;
+ res = nameof (I.M);
+ if (res != "M")
+ return 1;
+
+ res = nameof (I.Prop);
+ if (res != "Prop")
+ return 2;
+
+ return 0;
+ }
+}
\ No newline at end of file
</method>\r
</type>\r
</test>\r
+ <test name="test-nameof-01.cs">\r
+ <type name="X">\r
+ <method name="Int32 Main()" attrs="150">\r
+ <size>20</size>\r
+ </method>\r
+ <method name="Void .ctor()" attrs="6278">\r
+ <size>7</size>\r
+ </method>\r
+ </type>\r
+ </test>\r
+ <test name="test-nameof-02.cs">\r
+ <type name="A`1[T]">\r
+ <method name="Void .ctor()" attrs="6278">\r
+ <size>7</size>\r
+ </method>\r
+ </type>\r
+ <type name="A`1+B[T]">\r
+ <method name="Void .ctor()" attrs="6278">\r
+ <size>7</size>\r
+ </method>\r
+ </type>\r
+ <type name="X">\r
+ <method name="Int64 get_Prop()" attrs="2177">\r
+ <size>14</size>\r
+ </method>\r
+ <method name="Void set_Prop(Int64)" attrs="2177">\r
+ <size>8</size>\r
+ </method>\r
+ <method name="Void add_ev(System.Action)" attrs="2177">\r
+ <size>42</size>\r
+ </method>\r
+ <method name="Void remove_ev(System.Action)" attrs="2177">\r
+ <size>42</size>\r
+ </method>\r
+ <method name="Int32 Main()" attrs="150">\r
+ <size>83</size>\r
+ </method>\r
+ <method name="Void GenMethod[T,U,V]()" attrs="145">\r
+ <size>2</size>\r
+ </method>\r
+ <method name="Int32 SimpleName[T](T)" attrs="129">\r
+ <size>17</size>\r
+ </method>\r
+ <method name="Int32 MemberAccess()" attrs="129">\r
+ <size>10</size>\r
+ </method>\r
+ <method name="Int32 QualifiedName()" attrs="129">\r
+ <size>10</size>\r
+ </method>\r
+ <method name="Void .ctor()" attrs="6278">\r
+ <size>7</size>\r
+ </method>\r
+ </type>\r
+ </test>\r
+ <test name="test-nameof-03.cs">\r
+ <type name="T2">\r
+ <method name="Int32 nameof(System.String)" attrs="150">\r
+ <size>10</size>\r
+ </method>\r
+ </type>\r
+ <type name="X">\r
+ <method name="Int32 Main()" attrs="150">\r
+ <size>37</size>\r
+ </method>\r
+ <method name="Void .ctor()" attrs="6278">\r
+ <size>7</size>\r
+ </method>\r
+ </type>\r
+ </test>\r
+ <test name="test-nameof-04.cs">\r
+ <type name="Ambiguous">\r
+ <method name="Int32 Main()" attrs="150">\r
+ <size>68</size>\r
+ </method>\r
+ <method name="Void .ctor()" attrs="6278">\r
+ <size>7</size>\r
+ </method>\r
+ </type>\r
+ </test>\r
<test name="test-null-operator-01.cs">\r
<type name="S">\r
<method name="Int32 get_Prop()" attrs="2182">\r