Browse Source

2002-04-30 Miguel de Icaza <[email protected]>

	* assign.cs (CompoundAssign): A new class used as a "flag" that
	the assignment actually is happening as part of a compound
	assignment operator.

	During compound assignment, a few new rules exist to enable things
	like:

	byte b |= 1 + 2

	From the spec:

	x op= y can be evaluated as x = (T) (x op y) (ie, an explicit cast
	to the type of x) if y is implicitly convertible to the type of x,
	and the operator is a builtin operator and the return type of the
	operator is explicitly convertible to the type of x.

	* rootcontext.cs: Reset warning level to 2.  4 catches various
	"interesting" features in mcs, we must clean this up at some
	point, but currently am trying to kill other bugs ;-)

svn path=/trunk/mcs/; revision=4179
Miguel de Icaza 24 years ago
parent
commit
e19cb4f11d
7 changed files with 209 additions and 64 deletions
  1. 20 0
      mcs/mcs/ChangeLog
  2. 71 10
      mcs/mcs/assign.cs
  3. 60 40
      mcs/mcs/cs-parser.jay
  4. 14 2
      mcs/mcs/expression.cs
  5. 1 1
      mcs/mcs/rootcontext.cs
  6. 11 11
      mcs/tests/makefile
  7. 32 0
      mcs/tests/test-110.cs

+ 20 - 0
mcs/mcs/ChangeLog

@@ -1,5 +1,25 @@
 2002-04-30  Miguel de Icaza  <[email protected]>
 
+	* assign.cs (CompoundAssign): A new class used as a "flag" that
+	the assignment actually is happening as part of a compound
+	assignment operator.
+
+	During compound assignment, a few new rules exist to enable things
+	like:
+
+	byte b |= 1 + 2
+
+	From the spec:
+	
+	x op= y can be evaluated as x = (T) (x op y) (ie, an explicit cast
+	to the type of x) if y is implicitly convertible to the type of x,
+	and the operator is a builtin operator and the return type of the
+	operator is explicitly convertible to the type of x. 
+
+	* rootcontext.cs: Reset warning level to 2.  4 catches various
+	"interesting" features in mcs, we must clean this up at some
+	point, but currently am trying to kill other bugs ;-)
+
 	* ecore.cs (SimpleName.SimpleNameResolve): Perform member lookups
 	in container classes as well.  
 

+ 71 - 10
mcs/mcs/assign.cs

@@ -162,11 +162,8 @@ namespace Mono.CSharp {
 				return this;
 			}
 
-			if (target is IndexerAccess){
-				IndexerAccess ia = (IndexerAccess) target;
-
+			if (target is IndexerAccess)
 				return this;
-			}
 
 			if (target is EventExpr) {
 
@@ -211,12 +208,6 @@ namespace Mono.CSharp {
 				return n;
 			}
 
-			if (target_type != source_type){
-				source = ConvertImplicitRequired (ec, source, target_type, l);
-				if (source == null)
-					return null;
-			}
-
 			if (target.eclass != ExprClass.Variable && target.eclass != ExprClass.EventAccess){
 				Report.Error (131, l,
 					      "Left hand of an assignment must be a variable, " +
@@ -224,6 +215,56 @@ namespace Mono.CSharp {
 				return null;
 			}
 
+			if (target_type == source_type)
+				return this;
+			
+			//
+			// If this assignemnt/operator was part of a compound binary
+			// operator, then we allow an explicit conversion, as detailed
+			// in the spec. 
+			//
+
+			if (this is CompoundAssign){
+				CompoundAssign a = (CompoundAssign) this;
+				
+				a.original_source = a.original_source.Resolve (ec);
+				if (a.original_source == null)
+					return null;
+				
+				Binary b = source as Binary;
+				if (b != null && b.IsBuiltinOperator){
+					//
+					// 1. if the source is explicitly convertible to the
+					//    target_type
+					//
+					
+					source = ConvertExplicit (ec, source, target_type, l);
+					if (source == null){
+						Error_CannotConvertImplicit (l, source_type, target_type);
+						return null;
+					}
+				
+					//
+					// 2. and the original right side is implicitly convertible to
+					// the type of target_type.
+					//
+					a.original_source = a.original_source.Resolve (ec);
+					if (a.original_source == null){
+						Error_CannotConvertImplicit (l, source_type, target_type);
+						return null;
+					}
+					
+					if (StandardConversionExists (a.original_source, target_type))
+						return this;
+
+					return null;
+				}
+			}
+			
+			source = ConvertImplicitRequired (ec, source, target_type, l);
+			if (source == null)
+				return null;
+
 			return this;
 		}
 
@@ -265,6 +306,26 @@ namespace Mono.CSharp {
 			Emit (ec, true);
 		}
 	}
+
+	
+	//
+	// This is just a class used to flag that the assignment was part of a
+	// compound assignment, hence allowing a set of extra rules to be used.
+	//
+	class CompoundAssign : Assign {
+		public Expression original_source;
+		
+		public CompoundAssign (Expression target, Expression source, Expression osource, Location l)
+			: base (target, source, l)
+		{
+			original_source = osource;
+		}
+
+		public Expression ResolveSource (EmitContext ec)
+		{
+			return original_source.Resolve (ec);
+		}
+	}
 }
 
 

+ 60 - 40
mcs/mcs/cs-parser.jay

@@ -2495,91 +2495,111 @@ assignment_expression
 	  {
 		Location l = lexer.Location;
 
-		$$ = new Assign ((Expression) $1,
-				 new Binary (Binary.Operator.Multiply, 
-					     (Expression) $1,
-					     (Expression) $3, l), l);
+		$$ = new CompoundAssign (
+			(Expression) $1,
+			new Binary (Binary.Operator.Multiply, 
+				     (Expression) $1,
+				     (Expression) $3, l), 
+			(Expression) $3, l);
 	  }
 	| prefixed_unary_expression OP_DIV_ASSIGN expression
 	  {
 		Location l = lexer.Location;
 
-		$$ = new Assign ((Expression) $1,
-				 new Binary (Binary.Operator.Division, 
-					     (Expression) $1,
-					     (Expression) $3, l), l);
+		$$ = new CompoundAssign (
+			(Expression) $1,
+			new Binary (Binary.Operator.Division, 
+				     (Expression) $1,
+				     (Expression) $3, l),
+			(Expression) $3, l);
 	  }
 	| prefixed_unary_expression OP_MOD_ASSIGN expression
 	  {
 		Location l = lexer.Location;
 
-		$$ = new Assign ((Expression) $1,
-				 new Binary (Binary.Operator.Modulus, 
-					     (Expression) $1,
-					     (Expression) $3, l), l);
+		$$ = new CompoundAssign (
+			(Expression) $1,
+			new Binary (Binary.Operator.Modulus, 
+				     (Expression) $1,
+				     (Expression) $3, l),
+			(Expression) $3, l);
 	  }
 	| prefixed_unary_expression OP_ADD_ASSIGN expression
 	  {
 		Location l = lexer.Location;
 
-		$$ = new Assign ((Expression) $1,
-				 new Binary (Binary.Operator.Addition, 
-					     (Expression) $1,
-					     (Expression) $3, l), l);
+		$$ = new CompoundAssign (
+			(Expression) $1,
+			new Binary (Binary.Operator.Addition, 
+				     (Expression) $1,
+				     (Expression) $3, l),
+			(Expression) $3, l);
 	  }
 	| prefixed_unary_expression OP_SUB_ASSIGN expression
 	  {
 		Location l = lexer.Location;
 
-		$$ = new Assign ((Expression) $1,
-				 new Binary (Binary.Operator.Subtraction, 
-					     (Expression) $1,
-					     (Expression) $3, l), l);
+		$$ = new CompoundAssign (
+			(Expression) $1,
+			new Binary (Binary.Operator.Subtraction, 
+				     (Expression) $1,
+				     (Expression) $3, l),
+			(Expression) $3, l);
 	  }
 	| prefixed_unary_expression OP_SHIFT_LEFT_ASSIGN expression
 	  {
 		Location l = lexer.Location;
 
-		$$ = new Assign ((Expression) $1,
-				 new Binary (Binary.Operator.LeftShift, 
-					     (Expression) $1,
-					     (Expression) $3, l), l);
+		$$ = new CompoundAssign (
+			(Expression) $1,
+			new Binary (Binary.Operator.LeftShift, 
+				     (Expression) $1,
+				     (Expression) $3, l), 
+			(Expression) $3, l);
 	  }
 	| prefixed_unary_expression OP_SHIFT_RIGHT_ASSIGN expression
 	  {
 		Location l = lexer.Location;
 
-		$$ = new Assign ((Expression) $1,
-				 new Binary (Binary.Operator.RightShift, 
-					     (Expression) $1,
-					     (Expression) $3, l), l);
+		$$ = new CompoundAssign (
+			(Expression) $1,
+			new Binary (Binary.Operator.RightShift, 
+				     (Expression) $1,
+				     (Expression) $3, l), 
+			(Expression) $3, l);
 	  }
 	| prefixed_unary_expression OP_AND_ASSIGN expression
 	  {
 		Location l = lexer.Location;
 
-		$$ = new Assign ((Expression) $1,
-				 new Binary (Binary.Operator.BitwiseAnd, 
-					     (Expression) $1,
-					     (Expression) $3, l), l);
+		$$ = new CompoundAssign (
+			(Expression) $1,
+			new Binary (Binary.Operator.BitwiseAnd, 
+				     (Expression) $1,
+				     (Expression) $3, l),
+			(Expression) $3, l);
 	  }
 	| prefixed_unary_expression OP_OR_ASSIGN expression
 	  {
 		Location l = lexer.Location;
 
-		$$ = new Assign ((Expression) $1,
-				 new Binary (Binary.Operator.BitwiseOr, 
-					     (Expression) $1,
-					     (Expression) $3, l), l);
+		$$ = new CompoundAssign (
+			(Expression) $1,
+			new Binary (Binary.Operator.BitwiseOr, 
+				     (Expression) $1,
+				     (Expression) $3, l),
+			(Expression) $3, l);
 	  }
 	| prefixed_unary_expression OP_XOR_ASSIGN expression
 	  {
 		Location l = lexer.Location;
 
-		$$ = new Assign ((Expression) $1,
-				 new Binary (Binary.Operator.ExclusiveOr, 
-					     (Expression) $1,
-					     (Expression) $3, l), l);
+		$$ = new CompoundAssign (
+			(Expression) $1,
+			new Binary (Binary.Operator.ExclusiveOr, 
+				     (Expression) $1,
+				     (Expression) $3, l),
+			(Expression) $3, l);
 	  }
 	;
 

+ 14 - 2
mcs/mcs/expression.cs

@@ -1327,8 +1327,14 @@ namespace Mono.CSharp {
 
 		Operator oper;
 		Expression left, right;
-		MethodBase method;
+
+		//
+		// After resolution, method might contain the operator overload
+		// method.
+		//
+		protected MethodBase method;
 		ArrayList  Arguments;
+
 		Location   loc;
 
 		bool DelegateOperation;
@@ -1679,7 +1685,7 @@ namespace Mono.CSharp {
 			error19 ();
 			return null;
 		}
-		
+
 		Expression ResolveOperator (EmitContext ec)
 		{
 			Type l = left.Type;
@@ -2333,6 +2339,12 @@ namespace Mono.CSharp {
 
 			ig.Emit (opcode);
 		}
+
+		public bool IsBuiltinOperator {
+			get {
+				return method == null;
+			}
+		}
 	}
 
 	public class PointerArithmetic : Expression {

+ 1 - 1
mcs/mcs/rootcontext.cs

@@ -56,7 +56,7 @@ namespace Mono.CSharp {
 		//
 		static TypeBuilder impl_details_class;
 
-		public static int WarningLevel = 4;
+		public static int WarningLevel = 2;
 		
 		//
 		// Constructor

+ 11 - 11
mcs/tests/makefile

@@ -4,17 +4,17 @@ MCS=../mcs/mcs.exe
 VERIFY=../tools/verifier.exe
 
 TEST_SOURCES = \
-	test-1  test-2  test-3  test-4  test-5  test-6  test-7  test-8  test-9  test-10 \
-	test-11 test-12 test-13 test-14 test-15 test-16 test-17 test-18 test-19 test-20 \
-	test-21 test-22 test-23 test-24 test-25 test-26 test-27 test-28 	test-30	\
-	test-31 test-32 test-33 test-34 test-35 test-36	test-37 	test-39 test-40 \
-	test-41 test-42 test-43 test-44 test-45 test-46 test-47 test-48 test-49 test-50 \
-	test-51 test-52	test-53 test-54 test-55 test-56 test-57		test-59 	\
-	test-61	test-62 test-63	test-64 test-65 test-66 test-67 test-68 test-69 test-70	\
-	test-71 test-72 test-73 test-74 test-75 test-76 test-77 test-78 test-79 test-80 \
-	test-81 test-82 test-83 test-84         test-86 test-87 test-88 test-89 test-90 \
-	test-91 test-92 test-93 test-94 test-95 test-96 test-97 test-98 test-99 test-100 \
-	test-101 test-102 test-103 test-104 test-105 test-106 test-107  test-108 test-109
+	test-1   test-2   test-3   test-4   test-5   test-6   test-7   test-8   test-9   test-10 \
+	test-11  test-12  test-13  test-14  test-15  test-16  test-17  test-18  test-19  test-20 \
+	test-21  test-22  test-23  test-24  test-25  test-26  test-27  test-28  	 test-30	\
+	test-31  test-32  test-33  test-34  test-35  test-36  test-37           test-39  test-40 \
+	test-41  test-42  test-43  test-44  test-45  test-46  test-47  test-48  test-49  test-50 \
+	test-51  test-52  test-53  test-54  test-55  test-56  test-57  	        test-59  	 \
+	test-61	 test-62  test-63  test-64  test-65  test-66  test-67  test-68  test-69  test-70	\
+	test-71  test-72  test-73  test-74  test-75  test-76  test-77  test-78  test-79  test-80 \
+	test-81  test-82  test-83  test-84  	     test-86  test-87  test-88  test-89  test-90 \
+	test-91  test-92  test-93  test-94  test-95  test-96  test-97  test-98  test-99  test-100 \
+	test-101 test-102 test-103 test-104 test-105 test-106 test-107 test-108 test-109 test-110
 
 UNSAFE_SOURCES = \
 	unsafe-1 unsafe-2

+ 32 - 0
mcs/tests/test-110.cs

@@ -0,0 +1,32 @@
+//
+// Special test case for the Compound Assignment for the
+// second case (not the obvious one, but the one with 
+// implicit casts)
+
+using System;
+
+namespace test
+{
+        public class test
+        {
+                static int test_method(int vv)
+                {
+			byte b = 45;
+
+			// The cast below will force the expression into being
+			// a byte, and we basically make an explicit cast from
+			// the return of "<<" from int to byte (the right-side type
+			// of the compound assignemtn)
+                        b |= (byte)(vv << 1);
+
+                        return b;
+                }
+
+                public static int Main ()
+                {
+			if (test_method (1) != 47)
+				return 1;
+			return 0;
+                }
+        }
+}