--- /dev/null
+// CS0102: The type `Part' already contains a definition for `arg'
+// Line: 6
+
+partial class Part
+{
+ int arg;
+}
+
+partial class Part(int arg)
+{
+}
\ No newline at end of file
--- /dev/null
+// CS0177: The out parameter `o' must be assigned to before control leaves the current method
+// Line: 4
+
+class Test(out int o)
+{
+}
-// CS1525: Unexpected symbol `}', expecting `,', `{', or `where'
+// CS1525: Unexpected symbol `}', expecting `(', `,', `{', or `where'
// Line: 9
using System;
--- /dev/null
+// CS8800: `S': Static classes cannot have primary constructor
+// Line: 4
+
+static class S(int i)
+{
+}
\ No newline at end of file
--- /dev/null
+// CS9001: Only one part of a partial type can declare primary constructor parameters
+// Line: 8
+
+partial class Part(int arg)
+{
+}
+
+partial class Part(int arg)
+{
+}
\ No newline at end of file
--- /dev/null
+// CS9002: `S.S(long)': Instance constructor of type with primary constructor must specify `this' constructor initializer
+// Line: 6
+
+class S (int arg)
+{
+ public S (long l)
+ {
+ }
+}
--- /dev/null
+// CS9003: Primary constructor of type `Test<T>' has parameter of same name as type parameter `T'
+// Line: 4
+
+class Test<T>(T T)
+{
+}
--- /dev/null
+// CS9004: Primary constructor of type `Test' has parameter of same name as containing type
+// Line: 4
+
+class Test(object Test)
+{
+}
\ No newline at end of file
--- /dev/null
+// CS9005: Constructor initializer cannot access primary constructor parameters
+// Line: 7
+
+class Test(string s)
+{
+ public Test ()
+ : this (s)
+ {
+ }
+}
\ No newline at end of file
--- /dev/null
+// CS9006: An object reference is required to access primary constructor parameter `value'
+// Line: 8
+
+class X (double value)
+{
+ public static double Prop {
+ get {
+ return value;
+ }
+ }
+}
+
--- /dev/null
+// CS9007: Primary constructor parameter `value' is not available in this context when using ref or out modifier
+// Line: 12
+
+class X (ref double value)
+{
+ public double Prop {
+ get {
+ return value;
+ }
+ }
+}
+
{
flags |= Options.FieldInitializerScope | Options.ConstructorScope;
this.ctor_block = constructorContext.CurrentBlock.Explicit;
+
+ if (ctor_block.IsCompilerGenerated)
+ CurrentBlock = ctor_block;
}
public override ExplicitBlock ConstructorBlock {
}
}
+ class PrimaryConstructorAssign : SimpleAssign
+ {
+ readonly Field field;
+ readonly Parameter parameter;
+
+ public PrimaryConstructorAssign (Field field, Parameter parameter)
+ : base (null, null, parameter.Location)
+ {
+ this.field = field;
+ this.parameter = parameter;
+ }
+
+ protected override Expression DoResolve (ResolveContext rc)
+ {
+ target = new FieldExpr (field, loc);
+ source = rc.CurrentBlock.ParametersBlock.GetParameterInfo (parameter).CreateReferenceExpression (rc, loc);
+ return base.DoResolve (rc);
+ }
+
+ public override void EmitStatement (EmitContext ec)
+ {
+ using (ec.With (BuilderContext.Options.OmitDebugInfo, true)) {
+ base.EmitStatement (ec);
+ }
+ }
+ }
+
//
// This class is used for compound assignments.
//
}
}
+ public ParametersCompiled PrimaryConstructorParameters { get; set; }
+
public TypeParameters TypeParametersAll {
get {
return all_type_parameters;
if (symbol is TypeParameter) {
Report.Error (692, symbol.Location,
"Duplicate type parameter `{0}'", symbol.GetSignatureForError ());
+ } else if (symbol is PrimaryConstructorField && mc is TypeParameter) {
+ Report.Error (9003, symbol.Location, "Primary constructor of type `{0}' has parameter of same name as type parameter `{1}'",
+ symbol.Parent.GetSignatureForError (), symbol.GetSignatureForError ());
} else {
Report.Error (102, symbol.Location,
"The type `{0}' already contains a definition for `{1}'",
PartialContainer.containers.AddRange (containers);
}
+ if (PrimaryConstructorParameters != null) {
+ if (PartialContainer.PrimaryConstructorParameters != null) {
+ Report.Error (9001, Location, "Only one part of a partial type can declare primary constructor parameters");
+ } else {
+ PartialContainer.PrimaryConstructorParameters = PrimaryConstructorParameters;
+ }
+ }
+
members_defined = members_defined_ok = true;
caching_flags |= Flags.CloseTypeCreated;
} else {
public const TypeAttributes StaticClassAttribute = TypeAttributes.Abstract | TypeAttributes.Sealed;
SecurityType declarative_security;
+ protected Constructor generated_primary_constructor;
protected ClassOrStruct (TypeContainer parent, MemberName name, Attributes attrs, MemberKind kind)
: base (parent, name, attrs, kind)
{
}
+ public Arguments PrimaryConstructorBaseArguments { get; set; }
+
protected override TypeAttributes TypeAttr {
get {
TypeAttributes ta = base.TypeAttr;
symbol.GetSignatureForError ());
return;
}
+
+ if (symbol is PrimaryConstructorField) {
+ Report.Error (9004, symbol.Location, "Primary constructor of type `{0}' has parameter of same name as containing type",
+ symbol.Parent.GetSignatureForError ());
+ return;
+ }
InterfaceMemberBase imb = symbol as InterfaceMemberBase;
if (imb == null || !imb.IsExplicitImpl) {
mods = ((ModFlags & Modifiers.ABSTRACT) != 0) ? Modifiers.PROTECTED : Modifiers.PUBLIC;
}
- var c = new Constructor (this, MemberName.Name, mods, null, ParametersCompiled.EmptyReadOnlyParameters, Location);
- c.Initializer = new GeneratedBaseInitializer (Location);
+ var c = new Constructor (this, MemberName.Name, mods, null, PrimaryConstructorParameters ?? ParametersCompiled.EmptyReadOnlyParameters, Location);
+ if (Kind == MemberKind.Class)
+ c.Initializer = new GeneratedBaseInitializer (Location, PrimaryConstructorBaseArguments);
+
+ if (PrimaryConstructorParameters != null)
+ c.IsPrimaryConstructor = true;
AddConstructor (c, true);
- c.Block = new ToplevelBlock (Compiler, ParametersCompiled.EmptyReadOnlyParameters, Location) {
+ c.Block = new ToplevelBlock (Compiler, c.ParameterInfo, Location) {
IsCompilerGenerated = true
};
{
CheckProtectedModifier ();
+ if (PrimaryConstructorParameters != null) {
+ foreach (Parameter p in PrimaryConstructorParameters.FixedParameters) {
+ if ((p.ModFlags & Parameter.Modifier.RefOutMask) != 0)
+ continue;
+
+ var f = new PrimaryConstructorField (this, p);
+ AddField (f);
+
+ generated_primary_constructor.Block.AddStatement (
+ new StatementExpression (new PrimaryConstructorAssign (f, p), p.Location));
+ }
+ }
+
base.DoDefineMembers ();
return true;
Modifiers.SEALED |
Modifiers.STATIC |
Modifiers.UNSAFE;
-
+
public Class (TypeContainer parent, MemberName name, Modifiers mod, Attributes attrs)
: base (parent, name, attrs, MemberKind.Class)
{
}
if (IsStatic) {
+ if (PrimaryConstructorParameters != null) {
+ Report.Error (-800, Location, "`{0}': Static classes cannot have primary constructor", GetSignatureForError ());
+ PrimaryConstructorParameters = null;
+ }
+
foreach (var m in Members) {
if (m is Operator) {
Report.Error (715, m.Location, "`{0}': Static classes cannot contain user-defined operators", m.GetSignatureForError ());
Report.Error (708, m.Location, "`{0}': cannot declare instance members in a static class", m.GetSignatureForError ());
}
} else {
- if (!PartialContainer.HasInstanceConstructor)
- DefineDefaultConstructor (false);
+ if (!PartialContainer.HasInstanceConstructor || PrimaryConstructorParameters != null)
+ generated_primary_constructor = DefineDefaultConstructor (false);
}
return base.DoDefineMembers ();
return fts.CheckStructCycles ();
}
+ protected override bool DoDefineMembers ()
+ {
+ if (PrimaryConstructorParameters != null)
+ generated_primary_constructor = DefineDefaultConstructor (false);
+
+ return base.DoDefineMembers ();
+ }
+
public override void Emit ()
{
CheckStructCycles ();
Arglist = 1 << 5,
DefaultValue = 1 << 6,
- All = Ref | Out | This | Params | Arglist | DefaultValue
+ All = Ref | Out | This | Params | Arglist | DefaultValue,
+ PrimaryConstructor = Ref | Out | Params | DefaultValue
}
static readonly object ModifierNone = 0;
type_declaration_name
{
lexer.ConstraintsParsing = true;
+ valid_param_mod = ParameterModifierType.PrimaryConstructor;
push_current_container (new Struct (current_container, (MemberName) $6, (Modifiers) $2, (Attributes) $1), $3);
}
+ opt_primary_parameters
opt_class_base
opt_type_parameter_constraints_clauses
{
+ valid_param_mod = 0;
lexer.ConstraintsParsing = false;
- if ($9 != null)
- current_container.SetConstraints ((List<Constraints>) $9);
+ if ($8 != null)
+ current_type.PrimaryConstructorParameters = (ParametersCompiled) $8;
+
+ if ($10 != null)
+ current_container.SetConstraints ((List<Constraints>) $10);
if (doc_support)
current_container.PartialContainer.DocComment = Lexer.consume_doc_comment ();
opt_semicolon
{
if ($16 == null) {
- lbag.AppendToMember (current_container, GetLocation ($11), GetLocation ($14));
+ lbag.AppendToMember (current_container, GetLocation ($12), GetLocation ($15));
} else {
- lbag.AppendToMember (current_container, GetLocation ($11), GetLocation ($14), GetLocation ($16));
+ lbag.AppendToMember (current_container, GetLocation ($12), GetLocation ($15), GetLocation ($17));
}
$$ = pop_current_class ();
}
}
;
+opt_primary_parameters
+ : /* empty */
+ {
+ $$ = null;
+ }
+ | primary_parameters
+ ;
+
+primary_parameters
+ : OPEN_PARENS opt_formal_parameter_list CLOSE_PARENS
+ {
+ $$ = $2;
+
+ // Cannot use opt_formal_parameter_list because it can be shared instance for empty parameters
+ lbag.AppendToMember (current_container, GetLocation ($1), GetLocation ($3));
+ }
+ ;
+
+opt_primary_parameters_with_class_base
+ : /* empty */
+ {
+ $$ = null;
+ }
+ | class_base
+ {
+ $$ = null;
+ }
+ | primary_parameters
+ {
+ $$ = $1;
+ }
+ | primary_parameters class_base OPEN_PARENS
+ {
+ ++lexer.parsing_block;
+ }
+ opt_argument_list CLOSE_PARENS
+ {
+ lbag.AppendToMember (current_container, GetLocation ($3), GetLocation ($6));
+ ((Class)current_type).PrimaryConstructorBaseArguments = (Arguments) $5;
+ --lexer.parsing_block;
+
+ $$ = $1;
+ }
+ ;
+
//
// 10 classes
//
}
push_current_container (c, $3);
+ valid_param_mod = ParameterModifierType.PrimaryConstructor;
}
- opt_class_base
+ opt_primary_parameters_with_class_base
opt_type_parameter_constraints_clauses
{
+ valid_param_mod = 0;
lexer.ConstraintsParsing = false;
+ if ($8 != null)
+ current_type.PrimaryConstructorParameters = (ParametersCompiled) $8;
+
if ($9 != null)
current_container.SetConstraints ((List<Constraints>) $9);
lbag.AddMember (current_container, mod_locations, GetLocation ($4));
opt_class_base
: /* empty */
- | COLON type_list
+ | class_base
+ ;
+
+class_base
+ : COLON type_list
{
current_type.SetBaseTypes ((List<FullNamedExpression>) $2);
}
ct = ct.DeclaringType;
} while (ct != null);
+ } else {
+ var cos = rc.CurrentMemberDefinition.Parent as ClassOrStruct;
+ if (cos != null && cos.PrimaryConstructorParameters != null) {
+ foreach (var p in cos.PrimaryConstructorParameters.FixedParameters) {
+ if (p.Name == Name) {
+ rc.Report.Error (9007, loc, "Primary constructor parameter `{0}' is not available in this context when using ref or out modifier",
+ Name);
+ return null;
+ }
+ }
+ }
}
if ((restrictions & MemberLookupRestrictions.InvocableOnly) == 0) {
if (InstanceExpression == null || InstanceExpression is TypeExpr) {
if (InstanceExpression != null || !This.IsThisAvailable (rc, true)) {
- if (rc.HasSet (ResolveContext.Options.FieldInitializerScope))
+ if (rc.HasSet (ResolveContext.Options.FieldInitializerScope)) {
rc.Report.Error (236, loc,
"A field initializer cannot reference the nonstatic field, method, or property `{0}'",
GetSignatureForError ());
- else
- rc.Report.Error (120, loc,
- "An object reference is required to access non-static member `{0}'",
- GetSignatureForError ());
+ } else {
+ var fe = this as FieldExpr;
+ if (fe != null && fe.Spec.MemberDefinition is PrimaryConstructorField) {
+ if (rc.HasSet (ResolveContext.Options.BaseInitializer)) {
+ rc.Report.Error (9005, loc, "Constructor initializer cannot access primary constructor parameters");
+ } else {
+ rc.Report.Error (9006, loc, "An object reference is required to access primary constructor parameter `{0}'",
+ fe.Name);
+ }
+ } else {
+ rc.Report.Error (120, loc,
+ "An object reference is required to access non-static member `{0}'",
+ GetSignatureForError ());
+ }
+ }
InstanceExpression = new CompilerGeneratedThis (rc.CurrentType, loc).Resolve (rc);
return false;
return true;
}
}
+
+ class PrimaryConstructorField : Field
+ {
+ //
+ // Proxy resolved parameter type expression to avoid type double resolve
+ // and problems with correct resolve context on partial classes
+ //
+ sealed class TypeExpressionFromParameter : TypeExpr
+ {
+ Parameter parameter;
+
+ public TypeExpressionFromParameter (Parameter parameter)
+ {
+ this.parameter = parameter;
+ eclass = ExprClass.Type;
+ loc = parameter.Location;
+ }
+
+ public override TypeSpec ResolveAsType (IMemberContext mc)
+ {
+ return parameter.Type;
+ }
+ }
+
+ public PrimaryConstructorField (TypeDefinition parent, Parameter parameter)
+ : base (parent, new TypeExpressionFromParameter (parameter), Modifiers.PRIVATE, new MemberName (parameter.Name, parameter.Location), null)
+ {
+ caching_flags |= Flags.IsUsed | Flags.IsAssigned;
+ }
+
+ public override string GetSignatureForError ()
+ {
+ return MemberName.Name;
+ }
+ }
}
}
class GeneratedBaseInitializer: ConstructorBaseInitializer {
- public GeneratedBaseInitializer (Location loc):
- base (null, loc)
+ public GeneratedBaseInitializer (Location loc, Arguments arguments)
+ : base (arguments, loc)
{
}
}
}
}
+ public bool IsPrimaryConstructor { get; set; }
+
MethodBase IMethodDefinition.Metadata {
get {
if (!CheckBase ())
return false;
+ if (Parent.PrimaryConstructorParameters != null && !IsPrimaryConstructor) {
+ if (Parent.Kind == MemberKind.Struct) {
+ Report.Error (9009, Location, "`{0}': Structs with primary constructor cannot have explicit constructor",
+ GetSignatureForError ());
+ } else if (Initializer == null || Initializer is ConstructorBaseInitializer) {
+ Report.Error (9002, Location, "`{0}': Instance constructor of type with primary constructor must specify `this' constructor initializer",
+ GetSignatureForError ());
+ }
+ }
+
var ca = ModifiersExtensions.MethodAttr (ModFlags) | MethodAttributes.RTSpecialName | MethodAttributes.SpecialName;
ConstructorBuilder = Parent.TypeBuilder.DefineConstructor (
//
block.AddThisVariable (bc);
} else if (Parent.PartialContainer.Kind == MemberKind.Class) {
- Initializer = new GeneratedBaseInitializer (Location);
+ Initializer = new GeneratedBaseInitializer (Location, null);
}
}
}
static readonly string[] attribute_targets = new string[] { "param" };
+ static readonly string[] attribute_targets_primary = new string[] { "param", "field" };
FullNamedExpression texpr;
Modifier modFlags;
protected int idx;
public bool HasAddressTaken;
+ Constructor primary_constructor;
TemporaryVariableReference expr_tree_variable;
HoistedParameter hoisted_variant;
public override string[] ValidAttributeTargets {
get {
- return attribute_targets;
+ return primary_constructor != null ? attribute_targets_primary : attribute_targets;
}
}
public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
{
+ if (a.Target == AttributeTargets.Field) {
+ var field = MemberCache.FindMember (primary_constructor.Spec.DeclaringType, MemberFilter.Field (name, parameter_type), BindingRestriction.DeclaredOnly);
+ ((Field)field.MemberDefinition).ApplyAttributeBuilder (a, ctor, cdata, pa);
+ return;
+ }
+
if (a.Type == pa.In && ModFlags == Modifier.OUT) {
a.Report.Error (36, a.Location, "An out parameter cannot have the `In' attribute");
return;
if (attributes != null)
attributes.AttachTo (this, rc);
+ var ctor = rc.CurrentMemberDefinition as Constructor;
+ if (ctor != null && ctor.IsPrimaryConstructor)
+ primary_constructor = ctor;
+
parameter_type = texpr.ResolveAsType (rc);
if (parameter_type == null)
return null;
--- /dev/null
+class Simple(int arg)
+{
+ int Property {
+ get {
+ return arg;
+ }
+ }
+
+ public static int Main ()
+ {
+ var c = new Simple (4);
+ if (c.Property != 4)
+ return 1;
+
+ var s = new S (4.3m);
+ if (s.Property != 4.3m)
+ return 1;
+
+ return 0;
+ }
+}
+
+struct S(decimal arg)
+{
+ internal decimal Property {
+ get {
+ return arg;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+
+partial class Part
+{
+ public Part (string s)
+ : this (5)
+ {
+ if (arg != 5)
+ throw new ApplicationException ("1");
+
+ if (Property != 12)
+ throw new ApplicationException ("2");
+ }
+}
+
+partial class Part(int arg)
+{
+ int field = 7;
+
+ int Property {
+ get {
+ return arg + field;
+ }
+ }
+
+ public static int Main ()
+ {
+ var p = new Part ("5");
+ if (p.Property != 12)
+ return 1;
+
+ return 0;
+ }
+}
\ No newline at end of file
--- /dev/null
+class D(string arg) : Base (arg)
+{
+}
+
+abstract class Base (object obj)
+{
+ public string Prop { get { return obj.ToString (); } }
+}
+
+class X
+{
+ public static int Main ()
+ {
+ var d = new D ("test");
+ if (d.Prop != "test")
+ return 1;
+
+ return 0;
+ }
+}
\ No newline at end of file
--- /dev/null
+class Derived (int arg, ref byte b, out int o) : Base (out o)
+{
+ public long field = arg;
+ public int fieldRef = b;
+}
+
+class Base
+{
+ internal Base (out int o)
+ {
+ o = 8;
+ }
+}
+
+class X
+{
+ public static int Main ()
+ {
+ int arg;
+ byte b = 4;
+ var d = new Derived (-5, ref b, out arg);
+ if (d.field != -5)
+ return 1;
+
+ if (d.fieldRef != 4)
+ return 2;
+
+ System.Console.WriteLine ("ok");
+ return 0;
+ }
+}
\ No newline at end of file
--- /dev/null
+// Compiler options: -warnaserror
+
+using System;
+using System.Reflection;
+
+class A : Attribute
+{
+}
+
+class X ([field:A] int value)
+{
+ public int f = value;
+
+ public int P {
+ get {
+ return value;
+ }
+ }
+
+ public static int Main ()
+ {
+ var attr = (A)typeof (X).GetField("value", BindingFlags.NonPublic | BindingFlags.Instance).GetCustomAttribute (typeof (A));
+ if (attr == null)
+ return 1;
+
+ return 0;
+ }
+}
</method>\r
</type>\r
</test>\r
+ <test name="test-primary-ctor-01.cs">\r
+ <type name="Simple">\r
+ <method name="Int32 get_Property()" attrs="2177">\r
+ <size>15</size>\r
+ </method>\r
+ <method name="Int32 Main()" attrs="150">\r
+ <size>89</size>\r
+ </method>\r
+ <method name="Void .ctor(Int32)" attrs="6278">\r
+ <size>14</size>\r
+ </method>\r
+ </type>\r
+ <type name="S">\r
+ <method name="Decimal get_Property()" attrs="2179">\r
+ <size>15</size>\r
+ </method>\r
+ <method name="Void .ctor(Decimal)" attrs="6278">\r
+ <size>8</size>\r
+ </method>\r
+ </type>\r
+ </test>\r
+ <test name="test-primary-ctor-02.cs">\r
+ <type name="Part">\r
+ <method name="Int32 get_Property()" attrs="2177">\r
+ <size>22</size>\r
+ </method>\r
+ <method name="Int32 Main()" attrs="150">\r
+ <size>41</size>\r
+ </method>\r
+ <method name="Void .ctor(String)" attrs="6278">\r
+ <size>56</size>\r
+ </method>\r
+ <method name="Void .ctor(Int32)" attrs="6278">\r
+ <size>21</size>\r
+ </method>\r
+ </type>\r
+ </test>\r
+ <test name="test-primary-ctor-03.cs">\r
+ <type name="D">\r
+ <method name="Void .ctor(String)" attrs="6278">\r
+ <size>15</size>\r
+ </method>\r
+ </type>\r
+ <type name="Base">\r
+ <method name="System.String get_Prop()" attrs="2182">\r
+ <size>20</size>\r
+ </method>\r
+ <method name="Void .ctor(Object)" attrs="6276">\r
+ <size>14</size>\r
+ </method>\r
+ </type>\r
+ <type name="X">\r
+ <method name="Int32 Main()" attrs="150">\r
+ <size>49</size>\r
+ </method>\r
+ <method name="Void .ctor()" attrs="6278">\r
+ <size>7</size>\r
+ </method>\r
+ </type>\r
+ </test>\r
+ <test name="test-primary-ctor-04.cs">\r
+ <type name="Derived">\r
+ <method name="Void .ctor(Int32, Byte&, Int32&)" attrs="6278">\r
+ <size>31</size>\r
+ </method>\r
+ </type>\r
+ <type name="Base">\r
+ <method name="Void .ctor(Int32&)" attrs="6275">\r
+ <size>11</size>\r
+ </method>\r
+ </type>\r
+ <type name="X">\r
+ <method name="Int32 Main()" attrs="150">\r
+ <size>74</size>\r
+ </method>\r
+ <method name="Void .ctor()" attrs="6278">\r
+ <size>7</size>\r
+ </method>\r
+ </type>\r
+ </test>\r
+ <test name="test-primary-ctor-05.cs">\r
+ <type name="A">\r
+ <method name="Void .ctor()" attrs="6278">\r
+ <size>7</size>\r
+ </method>\r
+ </type>\r
+ <type name="X">\r
+ <method name="Int32 get_P()" attrs="2182">\r
+ <size>15</size>\r
+ </method>\r
+ <method name="Int32 Main()" attrs="150">\r
+ <size>66</size>\r
+ </method>\r
+ <method name="Void .ctor(Int32)" attrs="6278">\r
+ <size>21</size>\r
+ </method>\r
+ </type>\r
+ </test>\r
<test name="test-var-01.cs">\r
<type name="Test">\r
<method name="Int32 Main()" attrs="150">\r