[mcs] Primary constructors
authorMarek Safar <marek.safar@gmail.com>
Thu, 30 Jan 2014 16:52:26 +0000 (17:52 +0100)
committerMarek Safar <marek.safar@gmail.com>
Wed, 16 Apr 2014 09:40:07 +0000 (11:40 +0200)
24 files changed:
mcs/errors/cs0102-99.cs [new file with mode: 0644]
mcs/errors/cs0177-99.cs [new file with mode: 0644]
mcs/errors/cs1525-39.cs
mcs/errors/cs8800.cs [new file with mode: 0644]
mcs/errors/cs9001.cs [new file with mode: 0644]
mcs/errors/cs9002.cs [new file with mode: 0644]
mcs/errors/cs9003.cs [new file with mode: 0644]
mcs/errors/cs9004.cs [new file with mode: 0644]
mcs/errors/cs9005.cs [new file with mode: 0644]
mcs/errors/cs9006.cs [new file with mode: 0644]
mcs/errors/cs9007.cs [new file with mode: 0644]
mcs/mcs/assign.cs
mcs/mcs/class.cs
mcs/mcs/cs-parser.jay
mcs/mcs/ecore.cs
mcs/mcs/field.cs
mcs/mcs/method.cs
mcs/mcs/parameter.cs
mcs/tests/test-primary-ctor-01.cs [new file with mode: 0644]
mcs/tests/test-primary-ctor-02.cs [new file with mode: 0644]
mcs/tests/test-primary-ctor-03.cs [new file with mode: 0644]
mcs/tests/test-primary-ctor-04.cs [new file with mode: 0644]
mcs/tests/test-primary-ctor-05.cs [new file with mode: 0644]
mcs/tests/ver-il-net_4_5.xml

diff --git a/mcs/errors/cs0102-99.cs b/mcs/errors/cs0102-99.cs
new file mode 100644 (file)
index 0000000..b07a246
--- /dev/null
@@ -0,0 +1,11 @@
+// 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
diff --git a/mcs/errors/cs0177-99.cs b/mcs/errors/cs0177-99.cs
new file mode 100644 (file)
index 0000000..b221d46
--- /dev/null
@@ -0,0 +1,6 @@
+// CS0177: The out parameter `o' must be assigned to before control leaves the current method
+// Line: 4
+
+class Test(out int o) 
+{
+}
index 9bb3108643fa233b8cbd26040ab8dd3ab6658556..61b9d8ce5e8f0db4daa2e9fb6bdf253d769a8091 100644 (file)
@@ -1,4 +1,4 @@
-// CS1525: Unexpected symbol `}', expecting `,', `{', or `where'
+// CS1525: Unexpected symbol `}', expecting `(', `,', `{', or `where'
 // Line: 9
 
 using System;
diff --git a/mcs/errors/cs8800.cs b/mcs/errors/cs8800.cs
new file mode 100644 (file)
index 0000000..2952c7f
--- /dev/null
@@ -0,0 +1,6 @@
+// CS8800: `S': Static classes cannot have primary constructor
+// Line: 4
+
+static class S(int i)
+{
+}
\ No newline at end of file
diff --git a/mcs/errors/cs9001.cs b/mcs/errors/cs9001.cs
new file mode 100644 (file)
index 0000000..5969480
--- /dev/null
@@ -0,0 +1,10 @@
+// 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
diff --git a/mcs/errors/cs9002.cs b/mcs/errors/cs9002.cs
new file mode 100644 (file)
index 0000000..ea40954
--- /dev/null
@@ -0,0 +1,9 @@
+// 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)
+       {
+       }
+}
diff --git a/mcs/errors/cs9003.cs b/mcs/errors/cs9003.cs
new file mode 100644 (file)
index 0000000..00780bc
--- /dev/null
@@ -0,0 +1,6 @@
+// CS9003: Primary constructor of type `Test<T>' has parameter of same name as type parameter `T'
+// Line: 4
+
+class Test<T>(T T) 
+{
+}
diff --git a/mcs/errors/cs9004.cs b/mcs/errors/cs9004.cs
new file mode 100644 (file)
index 0000000..d367928
--- /dev/null
@@ -0,0 +1,6 @@
+// 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
diff --git a/mcs/errors/cs9005.cs b/mcs/errors/cs9005.cs
new file mode 100644 (file)
index 0000000..85e4c01
--- /dev/null
@@ -0,0 +1,10 @@
+// CS9005: Constructor initializer cannot access primary constructor parameters
+// Line: 7
+
+class Test(string s)
+{
+       public Test ()
+               : this (s)
+       {
+       }
+}
\ No newline at end of file
diff --git a/mcs/errors/cs9006.cs b/mcs/errors/cs9006.cs
new file mode 100644 (file)
index 0000000..4420f2f
--- /dev/null
@@ -0,0 +1,12 @@
+// 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;
+               }
+       }
+}
+
diff --git a/mcs/errors/cs9007.cs b/mcs/errors/cs9007.cs
new file mode 100644 (file)
index 0000000..05e9e3d
--- /dev/null
@@ -0,0 +1,12 @@
+// 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;
+               }
+       }
+}
+
index 97125dbaf04a4ec3d78b76e049ce1efbac60be8a..356768d8b74ed13484ade69a1340bdf5238bc9b6 100644 (file)
@@ -564,6 +564,9 @@ namespace Mono.CSharp {
                        {
                                flags |= Options.FieldInitializerScope | Options.ConstructorScope;
                                this.ctor_block = constructorContext.CurrentBlock.Explicit;
+
+                               if (ctor_block.IsCompilerGenerated)
+                                       CurrentBlock = ctor_block;
                        }
 
                        public override ExplicitBlock ConstructorBlock {
@@ -662,6 +665,33 @@ namespace Mono.CSharp {
                }
        }
 
+       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.
        //
index 731e1198d3ef0e8f35ca88603bf4645715e8c077..158be4dbe72d66efc18edcfa07d60a52b52838c7 100644 (file)
@@ -730,6 +730,8 @@ namespace Mono.CSharp
                        }
                }
 
+               public ParametersCompiled PrimaryConstructorParameters { get; set; }
+
                public TypeParameters TypeParametersAll {
                        get {
                                return all_type_parameters;
@@ -810,6 +812,9 @@ namespace Mono.CSharp
                        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}'",
@@ -1519,6 +1524,14 @@ namespace Mono.CSharp
                                        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 {
@@ -2511,12 +2524,15 @@ namespace Mono.CSharp
                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;
@@ -2544,6 +2560,12 @@ namespace Mono.CSharp
                                                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) {
@@ -2594,11 +2616,15 @@ namespace Mono.CSharp
                                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
                        };
 
@@ -2609,6 +2635,19 @@ namespace Mono.CSharp
                {
                        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;
@@ -2648,7 +2687,7 @@ namespace Mono.CSharp
                        Modifiers.SEALED |
                        Modifiers.STATIC |
                        Modifiers.UNSAFE;
-
+                       
                public Class (TypeContainer parent, MemberName name, Modifiers mod, Attributes attrs)
                        : base (parent, name, attrs, MemberKind.Class)
                {
@@ -2718,6 +2757,11 @@ namespace Mono.CSharp
                        }
 
                        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 ());
@@ -2745,8 +2789,8 @@ namespace Mono.CSharp
                                        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 ();
@@ -2968,6 +3012,14 @@ namespace Mono.CSharp
                        return fts.CheckStructCycles ();
                }
 
+               protected override bool DoDefineMembers ()
+               {
+                       if (PrimaryConstructorParameters != null)
+                               generated_primary_constructor = DefineDefaultConstructor (false);
+
+                       return base.DoDefineMembers ();
+               }
+
                public override void Emit ()
                {
                        CheckStructCycles ();
index 76425021a59b692cbd76c4af5fc1f90861d84f28..ad23569d641cb2a32c630481f7da0df1c95a312c 100644 (file)
@@ -35,7 +35,8 @@ namespace Mono.CSharp
                        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;
@@ -945,15 +946,21 @@ struct_declaration
          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 ();
@@ -976,9 +983,9 @@ struct_declaration
          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 ();
          }
@@ -4626,6 +4633,51 @@ boolean_expression
          }
        ;
 
+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
 //
@@ -4646,12 +4698,17 @@ class_declaration
                }
                        
                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));
@@ -4805,7 +4862,11 @@ modifier
        
 opt_class_base
        : /* empty */
-       | COLON type_list
+       | class_base
+       ;
+
+class_base
+       : COLON type_list
         {
                current_type.SetBaseTypes ((List<FullNamedExpression>) $2);
         }
index 0b73b3656cbdf5ace5d59645ffb7b33c81999ef3..8f3f5d64ba2c9de0f16df569874ed5280bfa1757 100644 (file)
@@ -2780,6 +2780,17 @@ namespace Mono.CSharp {
 
                                                                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) {
@@ -3416,14 +3427,25 @@ namespace Mono.CSharp {
 
                        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;
index fa3b07334da6f9a6e2d458de502e49e0df54ed8d..4b0b21685993678e3891b45c005db46cbadaf61d 100644 (file)
@@ -689,4 +689,39 @@ namespace Mono.CSharp
                        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;
+               }
+       }
 }
index 8a1e28d441fb1c6b4fcf5e6474b5ee88f5e84b98..8cd899b7b27efc4f81abca15c5267a1723fe79da 100644 (file)
@@ -1524,8 +1524,8 @@ namespace Mono.CSharp {
        }
 
        class GeneratedBaseInitializer: ConstructorBaseInitializer {
-               public GeneratedBaseInitializer (Location loc):
-                       base (null, loc)
+               public GeneratedBaseInitializer (Location loc, Arguments arguments)
+                       : base (arguments, loc)
                {
                }
        }
@@ -1585,6 +1585,8 @@ namespace Mono.CSharp {
                    }
                }
 
+               public bool IsPrimaryConstructor { get; set; }
+
                
                MethodBase IMethodDefinition.Metadata {
                        get {
@@ -1673,6 +1675,16 @@ namespace Mono.CSharp {
                        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 (
@@ -1744,7 +1756,7 @@ namespace Mono.CSharp {
                                                        //
                                                        block.AddThisVariable (bc);
                                                } else if (Parent.PartialContainer.Kind == MemberKind.Class) {
-                                                       Initializer = new GeneratedBaseInitializer (Location);
+                                                       Initializer = new GeneratedBaseInitializer (Location, null);
                                                }
                                        }
 
index da2b13e4ab69e7fd6949e65c4f065eced3f065e7..3580610523535606e4dd05174f7eb2107440a41c 100644 (file)
@@ -223,6 +223,7 @@ namespace Mono.CSharp {
                }
 
                static readonly string[] attribute_targets = new string[] { "param" };
+               static readonly string[] attribute_targets_primary = new string[] { "param", "field" };
 
                FullNamedExpression texpr;
                Modifier modFlags;
@@ -233,6 +234,7 @@ namespace Mono.CSharp {
                protected int idx;
                public bool HasAddressTaken;
 
+               Constructor primary_constructor;
                TemporaryVariableReference expr_tree_variable;
 
                HoistedParameter hoisted_variant;
@@ -307,7 +309,7 @@ namespace Mono.CSharp {
 
                public override string[] ValidAttributeTargets {
                        get {
-                               return attribute_targets;
+                               return primary_constructor != null ? attribute_targets_primary : attribute_targets;
                        }
                }
 
@@ -315,6 +317,12 @@ namespace Mono.CSharp {
 
                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;
@@ -382,6 +390,10 @@ namespace Mono.CSharp {
                        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;
diff --git a/mcs/tests/test-primary-ctor-01.cs b/mcs/tests/test-primary-ctor-01.cs
new file mode 100644 (file)
index 0000000..dac84c8
--- /dev/null
@@ -0,0 +1,30 @@
+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
diff --git a/mcs/tests/test-primary-ctor-02.cs b/mcs/tests/test-primary-ctor-02.cs
new file mode 100644 (file)
index 0000000..5369a49
--- /dev/null
@@ -0,0 +1,34 @@
+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
diff --git a/mcs/tests/test-primary-ctor-03.cs b/mcs/tests/test-primary-ctor-03.cs
new file mode 100644 (file)
index 0000000..d6e472e
--- /dev/null
@@ -0,0 +1,20 @@
+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
diff --git a/mcs/tests/test-primary-ctor-04.cs b/mcs/tests/test-primary-ctor-04.cs
new file mode 100644 (file)
index 0000000..55636ab
--- /dev/null
@@ -0,0 +1,31 @@
+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
diff --git a/mcs/tests/test-primary-ctor-05.cs b/mcs/tests/test-primary-ctor-05.cs
new file mode 100644 (file)
index 0000000..503e944
--- /dev/null
@@ -0,0 +1,28 @@
+// 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;
+       }
+}
index 0ad10a47f8000f941d1583547dfd1e5ff9863441..69cf7878810f3f7c993d443dfd15e8e1d3c5c395 100644 (file)
       </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&amp;, Int32&amp;)" attrs="6278">\r
+        <size>31</size>\r
+      </method>\r
+    </type>\r
+    <type name="Base">\r
+      <method name="Void .ctor(Int32&amp;)" 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