This is the mail archive of the java-patches@gcc.gnu.org mailing list for the Java project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[gcjx] Patch: FYI: enhanced for and boxing


I'm checking this in on the gcjx branch.

This updates the enhanced 'for' code to handle automatic boxing and
unboxing as needed.

Tom

Index: ChangeLog
from  Tom Tromey  <tromey@redhat.com>
	* model/forenhanced.hh (model_for_enhanced::elt_type): New field.
	(model_for_enhanced): Initialize it.
	(model_for_enhanced::get_element_type): New method.
	* bytecode/generate.hh
	(bytecode_generator::emit_cast_maybe_boxing): Declare.
	* bytecode/generate.cc (emit_cast_maybe_boxing): New method.
	(visit_cast): Use it.
	(visit_for_enhanced): Likewise.
	* model/forenhanced.cc (resolve): Removed error for primitive
	type; do assignment conversion in both cases.
	(find_method): New function.

Index: bytecode/generate.cc
===================================================================
RCS file: /cvs/gcc/gcc/gcjx/bytecode/Attic/generate.cc,v
retrieving revision 1.1.2.19
diff -u -r1.1.2.19 generate.cc
--- bytecode/generate.cc 12 Jul 2005 17:34:59 -0000 1.1.2.19
+++ bytecode/generate.cc 12 Sep 2005 01:34:38 -0000
@@ -684,7 +684,11 @@
 	increase_stack (container->type ()->element_type ());
 
 	// If needed, emit a cast to the iteration variable type.
-	emit_cast (var->type (), container->type ()->element_type ());
+	{
+	  push_expr_target push (this, ON_STACK);
+	  emit_cast_maybe_boxing (fstmt, var->type (),
+				  container->type ()->element_type ());
+	}
 	emit_store (var->type (), user_var);
 
 	target_map[fstmt] = std::make_pair (update, done);
@@ -718,6 +722,7 @@
 	model_method *has_next_meth
 	  = find_method ("hasNext", iterator_type, NULL,
 			 primitive_boolean_type, fstmt);
+	// FIXME: wrong for generics?
 	model_method *next_meth
 	  = find_method ("next", iterator_type, NULL, object_type,
 			 fstmt);
@@ -759,9 +764,11 @@
 	increase_stack (object_type);
 
 	// Cast to the user's type.
-	// FIXME: this doesn't work for unboxing.  In that case we
-	// must first cast to the iterator's element type.
-	emit_cast (var->type (), object_type);
+	{
+	  push_expr_target push (this, ON_STACK);
+	  emit_cast_maybe_boxing (fstmt, var->type (),
+				  fstmt->get_element_type ());
+	}
 
 	emit_store (var->type (), user_var);
 	body->visit (this);
@@ -2214,21 +2221,11 @@
 }
 
 void
-bytecode_generator::visit_cast (model_cast *cast_expr,
-				const ref_forwarding_type &dest,
-				const ref_expression &expr)
+bytecode_generator::emit_cast_maybe_boxing (model_element *request,
+					    model_type *dest_type,
+					    model_type *expr_type)
 {
-  assert (expr_target == ON_STACK || expr_target == STRING
-	  || expr_target == CONDITIONAL || expr_target == IGNORE);
-  {
-    push_expr_target push (this, (expr_target == CONDITIONAL
-				  ? CONDITIONAL
-				  : ON_STACK));
-    expr->visit (this);
-  }
-
-  model_type *dest_type = dest->type ();
-  if (dest_type->primitive_p () != expr->type ()->primitive_p ())
+  if (dest_type->primitive_p () != expr_type->primitive_p ())
     {
       if (dest_type->primitive_p ())
 	{
@@ -2237,26 +2234,23 @@
 	  // get_pretty_name here is a bit of an abuse.  Note that
 	  // Character doesn't have all the methods from Number, so we
 	  // need a special case here.
-	  std::string method_name;
-	  bool is_char = false;
 	  model_type *tmp_dest_type = dest_type;
-	  if (expr->type () == global->get_compiler ()->java_lang_Character ())
-	    {
-	      is_char = true;
-	      method_name = "charValue";
-	      tmp_dest_type = primitive_char_type;
-	    }
-	  else
-	    method_name = dest_type->get_pretty_name () + "Value";
+	  if (expr_type == global->get_compiler ()->java_lang_Character ())
+	    tmp_dest_type = primitive_char_type;
+	  std::string method_name = (tmp_dest_type->get_pretty_name ()
+				     + "Value");
 	  model_method *call
 	    = find_method (method_name.c_str (),
-			   assert_cast<model_class *> (expr->type ()),
-			   NULL, tmp_dest_type, cast_expr);
+			   assert_cast<model_class *> (expr_type),
+			   NULL, tmp_dest_type, request);
 	  std::list<ref_expression> args;
 	  handle_invocation (op_invokevirtual, call->get_declaring_class (),
 			     call, args);
-	  if (is_char)
-	    emit_cast (dest_type, primitive_char_type);
+	  if (tmp_dest_type != dest_type)
+	    {
+	      assert (tmp_dest_type == primitive_char_type);
+	      emit_cast (dest_type, primitive_char_type);
+	    }
 	}
       else
 	{
@@ -2265,21 +2259,21 @@
 	  // conversion.
 	  model_class *dest_class = assert_cast<model_class *> (dest_type);
 	  model_method *call = find_method ("valueOf", dest_class,
-					    expr->type (), dest_class,
-					    cast_expr);
+					    expr_type, dest_class,
+					    request);
 	  // We do pass an argument, but sneakily: we pushed it up
 	  // above.
 	  std::list<ref_expression> args;
 	  handle_invocation (op_invokestatic, dest_class, call, args);
 	  // We have to pop this ourselves due to lying to
 	  // handle_invocation.
-	  reduce_stack (expr->type ());
+	  reduce_stack (expr_type);
 	}
     }
   else
     {
-      class_writer::check_type (cast_expr, dest_type);
-      emit_cast (dest_type, expr->type ());
+      class_writer::check_type (request, dest_type);
+      emit_cast (dest_type, expr_type);
       if (expr_target == IGNORE)
 	{
 	  // This can only happen when accessing a static member with
@@ -2291,6 +2285,23 @@
 }
 
 void
+bytecode_generator::visit_cast (model_cast *cast_expr,
+				const ref_forwarding_type &dest,
+				const ref_expression &expr)
+{
+  assert (expr_target == ON_STACK || expr_target == STRING
+	  || expr_target == CONDITIONAL || expr_target == IGNORE);
+  {
+    push_expr_target push (this, (expr_target == CONDITIONAL
+				  ? CONDITIONAL
+				  : ON_STACK));
+    expr->visit (this);
+  }
+
+  emit_cast_maybe_boxing (cast_expr, dest->type (), expr->type ());
+}
+
+void
 bytecode_generator::visit_class_ref (model_class_ref *ref,
 				     const ref_forwarding_type &req)
 {
Index: bytecode/generate.hh
===================================================================
RCS file: /cvs/gcc/gcc/gcjx/bytecode/Attic/generate.hh,v
retrieving revision 1.1.2.8
diff -u -r1.1.2.8 generate.hh
--- bytecode/generate.hh 11 Jul 2005 16:41:48 -0000 1.1.2.8
+++ bytecode/generate.hh 12 Sep 2005 01:34:38 -0000
@@ -280,6 +280,7 @@
 		    const ref_expression &);
 
   void emit_cast (model_type *, model_type *);
+  void emit_cast_maybe_boxing (model_element *, model_type *, model_type *);
 
   void handle_comparison (java_opcode,
 			  const ref_expression &,
Index: model/forenhanced.cc
===================================================================
RCS file: /cvs/gcc/gcc/gcjx/model/Attic/forenhanced.cc,v
retrieving revision 1.1.2.1
diff -u -r1.1.2.1 forenhanced.cc
--- model/forenhanced.cc 13 Jan 2005 03:18:36 -0000 1.1.2.1
+++ model/forenhanced.cc 12 Sep 2005 01:34:38 -0000
@@ -1,6 +1,6 @@
 // Enhanced for loop.
 
-// Copyright (C) 2004 Free Software Foundation, Inc.
+// Copyright (C) 2004, 2005 Free Software Foundation, Inc.
 //
 // This file is part of GCC.
 //
@@ -21,6 +21,37 @@
 
 #include "typedefs.hh"
 
+// A helper function to find a no-argument method in a class.
+// Issues error and returns null if no match or ambiguous match.
+static model_method *
+find_method (resolution_scope *scope, model_element *where, model_class *klass,
+	     const std::string &name)
+{
+  std::set<model_method *> methods;
+  klass->find_members (name, methods, scope->get_current_class (), klass);
+  if (methods.empty ())
+    {
+      std::cerr << where->error ("couldn't find method %1 for type %2")
+	% name % klass;
+      return NULL;
+    }
+
+  model_method *candidate = NULL;
+  for (std::set<model_method *>::const_iterator i = methods.begin ();
+       i != methods.end ();
+       ++i)
+    {
+      if ((*i)->get_parameter_count () == 0)
+	{
+	  if (candidate != NULL)
+	    abort ();	// FIXME
+	  candidate = *i;
+	}
+    }
+  if (! candidate) abort (); 	// FIXME
+  return candidate;
+}
+
 void
 model_for_enhanced::resolve (resolution_scope *scope)
 {
@@ -35,14 +66,7 @@
       // Ok.  We pull this out so we don't try to load Iterable unless
       // really necessary.  This is a little strange but it does let
       // users iterate over arrays even with an older class library.
-
-      if (! assignment_conversion (variable->type (),
-				   expression->type ()->element_type ()))
-	std::cerr << expression->error ("%<for%> expression of type %1"
-					" is not assignment compatible with"
-					" variable of type %2")
-	  % expression->type ()->element_type ()
-	  % variable->type ();
+      elt_type = expression->type ()->element_type ();
     }
   else
     {
@@ -54,13 +78,38 @@
 					" implement %<java.lang.Iterable%>")
 	  % expression->type ();
 
-      if (! variable->type ()->reference_p ())
-	std::cerr << variable->error ("%<for%> variable has primitive type");
-
-      // FIXME: generics: if expression has parameterized type, the
-      // variable must be compatible with the parameter.
+      // Find the type of the iterator.  This is fairly roundabout --
+      // we find the 'iterator' method, then look at its return type
+      // for the 'next' method.  This seems robust, if lengthy.
+      model_class *expr_class
+	= assert_cast<model_class *> (expression->type ());
+      model_method *iterator = find_method (scope, expression.get (),
+					    expr_class, "iterator");
+      if (iterator)
+	{
+	  model_type *rtype = iterator->get_return_type ();
+	  if (! rtype->reference_p ())
+	    {
+	      // FIXME
+	      abort ();
+	    }
+	  model_class *rclass = assert_cast<model_class *> (rtype);
+	  model_method *next = find_method (scope, expression.get (),
+					    rclass, "next");
+	  if (next)
+	    elt_type = next->get_return_type ();
+	}
     }
 
+  // If ELT_TYPE is NULL, we have already issued an error.
+  if (elt_type != NULL
+      && ! assignment_conversion (variable->type (), elt_type))
+    std::cerr << expression->error ("%<for%> expression of type %1"
+				    " is not assignment compatible with"
+				    " variable of type %2")
+      % elt_type
+      % variable->type ();
+
   scope->add_binding (variable.get ());
   body->resolve (scope);
 }
Index: model/forenhanced.hh
===================================================================
RCS file: /cvs/gcc/gcc/gcjx/model/Attic/forenhanced.hh,v
retrieving revision 1.1.2.1
diff -u -r1.1.2.1 forenhanced.hh
--- model/forenhanced.hh 13 Jan 2005 03:18:36 -0000 1.1.2.1
+++ model/forenhanced.hh 12 Sep 2005 01:34:38 -0000
@@ -1,6 +1,6 @@
 // The enhanced for statement.
 
-// Copyright (C) 2004 Free Software Foundation, Inc.
+// Copyright (C) 2004, 2005 Free Software Foundation, Inc.
 //
 // This file is part of GCC.
 //
@@ -30,6 +30,9 @@
   // Variable declaration.
   ref_variable_decl variable;
 
+  // Type of the elements of the collection.
+  model_type *elt_type;
+
 public:
 
   model_for_enhanced (const location &w,
@@ -37,7 +40,8 @@
 		      const ref_expression &e)
     : model_for_base (w),
       expression (e),
-      variable (v)
+      variable (v),
+      elt_type (NULL)
   {
   }
 
@@ -46,6 +50,11 @@
   void compute_normal_completion (normal_completion_state &);
 
   void visit (visitor *v);
+
+  model_type *get_element_type () const
+  {
+    return elt_type;
+  }
 };
 
 #endif // GCJX_MODEL_FORENHANCED_HH


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]