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: more type inference work


I'm checking this in on the gcjx branch.

This fixes some bugs in type inference.

First, model_memberref_forward had to implement
use_assignment_conversion(); otherwise forwarded method invocations
never saw the type.

Second, this adds code to the type inferencer to handle the return
type.  This is still a bit incomplete.

Finally this adds some code to handle '>>' constraints a bit better.
This is also still a bit incomplete.

Now we can compile this program:

    class iter2a<T> { }

    class iter2b<K,V> {
      <T> iter2a<T> get() { return null; }
    }

    class iter2<T> {
      private iter2b<T, String> map;

      public iter2a<T> get() { return map.get(); }
    }

Tom

Index: ChangeLog
from  Tom Tromey  <tromey@redhat.com>

	* model/memberref.cc (resolve): Call use_assignment_conversion.
	* model/memberref.hh
	(model_memberref_forward::use_assignment_conversion): New method.
	(model_memberref_forward::assign_conv_type): New field.
	(model_memberref_forward): Initialize it.
	* unify.hh (unify): Added declared_return_type argument.  Changed
	type of assignment_type argument.
	* model/method.cc (method_conversion_p): Pass declared return
	type to unify.
	* unify.cc (unifier::consider_lubs): New method.  Don't update
	map if computed LUB is NULL.
	(unifier::declared_return_type): New field.
	(unifier::assign_conv_type): Likewise.
	(unifier): Added new arguments.
	(unify): Updated.
	(unifier::infer_as_object): New method.
	(unifier::consider_return_type): New method.
	(unifier::resolve_constraints): Use consider_lubs,
	consider_return_type, infer_as_object.
	(unifier::mapping_complete_p): Removed.
	(unifier::unify): Added more code for the '>>' case.

Index: unify.hh
===================================================================
--- unify.hh	(revision 105944)
+++ unify.hh	(working copy)
@@ -25,6 +25,7 @@
 /// Perform type inference according to the algorithm in the JLS.
 /// @param actual the actual argument types
 /// @param method the method being invoked
+/// @param declared_return_type the declared return type of the method
 /// @param assignment_type if not null, the type to which the result
 /// of this method is converted by assignment conversion.  If no
 /// assignment conversion is performed, should be NULL.
@@ -33,7 +34,8 @@
 void
 unify (const std::list<model_type *> &actual,
        model_method *method,
-       model_class *assignment_type,
+       model_type *declared_return_type,
+       model_type *assignment_type,
        model_type_map &result);
 
 /// Compute the LUB of two classes.
Index: model/memberref.cc
===================================================================
--- model/memberref.cc	(revision 105944)
+++ model/memberref.cc	(working copy)
@@ -49,6 +49,8 @@
 	real->set_left_hand_side (is_compound);
     }
   assert (real);
+  if (assign_conv_type)
+    real->use_assignment_conversion (assign_conv_type);
   real->resolve (scope);
   set_type (real->type ());
 }
Index: model/method.cc
===================================================================
--- model/method.cc	(revision 106661)
+++ model/method.cc	(working copy)
@@ -310,9 +310,7 @@
       model_type_map typeargs;
       // FIXME: error detection?
       // FIXME: pass in argument for varargs handling.
-      // FIXME: this dynamic_cast is probably wrong, we should
-      // fix the type inferencer.
-      unify (args, this, dynamic_cast<model_class *> (assign_type), typeargs);
+      unify (args, this, return_type->type (), assign_type, typeargs);
       return do_method_conversion_p (typeargs, args, phase);
     }
   return do_method_conversion_p (args, phase);
Index: model/memberref.hh
===================================================================
--- model/memberref.hh	(revision 105944)
+++ model/memberref.hh	(working copy)
@@ -69,6 +69,10 @@
   // True if compound assignment.
   bool is_compound;
 
+  // The type to which assignment conversion will be performed.  If
+  // NULL, this member won't be subject to assignment conversion.
+  model_type *assign_conv_type;
+
   bool compute_constant_p ()
   {
     return real->constant_p ();
@@ -81,7 +85,8 @@
     : model_memberref_base (w),
       is_call (false),
       is_lhs (false),
-      is_compound (false)
+      is_compound (false),
+      assign_conv_type (NULL)
   {
   }
 
@@ -92,7 +97,8 @@
       ids (l),
       is_call (false),
       is_lhs (false),
-      is_compound (false)
+      is_compound (false),
+      assign_conv_type (NULL)
   {
   }
 
@@ -140,6 +146,12 @@
     is_lhs = true;
     is_compound = compound;
   }
+
+  void use_assignment_conversion (model_type *t)
+  {
+    assert (! real);
+    assign_conv_type = t;
+  }
 };
 
 /// This form of a deferred member reference is used only when reading
Index: unify.cc
===================================================================
--- unify.cc	(revision 105952)
+++ unify.cc	(working copy)
@@ -48,8 +48,16 @@
   std::list<ref_element> gcpro;
 
   // Location we should use when creating things.
+  // FIXME: a request element would be better.
   location where;
 
+  // The declared return type of the method.
+  model_type *declared_return_type;
+
+  // If not NULL, the type to which assignment conversion of the
+  // result will occur.
+  model_class *assign_conv_type;
+
   typedef enum
     {
       LESS_THAN = 0,
@@ -380,6 +388,8 @@
     model_class_instance *actualci
       = assert_cast<model_class_instance *> (actual);
 
+    // FIXME: for '>' case we need special handling if ACTUAL's parent
+    // is not the same as FORMAL's parent.
     // FIXME: check that ACTUAL "inherits from FORMAL's erasure".
     // For '<' case only.
 
@@ -400,7 +410,21 @@
 	  {
 	    if (constraint == GREATER_THAN)
 	      {
-		// FIXME.
+		if (inner_a->wildcard_p ())
+		  {
+		    model_class *bound = inner_a_w->get_bound ();
+		    if (inner_a_w->super_p ())
+		      unify (LESS_THAN, bound, inner_f);
+		    else
+		      {
+			// FIXME: is replacing the bound here ok?
+			if (! bound)
+			  bound = global->get_compiler ()->java_lang_Object ();
+			unify (GREATER_THAN, bound, inner_f);
+		      }
+		  }
+		else
+		  unify (EQUAL, inner_a, inner_f);
 	      }
 	    else
 	      unify (EQUAL, inner_a, inner_f);
@@ -479,19 +503,6 @@
       }
   }
 
-  bool mapping_complete_p ()
-  {
-    for (std::set<model_type_variable *>::const_iterator i
-	   = formal_type_params.begin ();
-	 i != formal_type_params.end ();
-	 ++i)
-      {
-	if (mapping.find (*i) == mapping.end ())
-	  return false;
-      }
-    return true;
-  }
-
   void update_constraint_set (constraint_type type,
 			      model_type_variable *var,
 			      std::set<model_class *> &result)
@@ -506,9 +517,9 @@
       }
   }
 
-  void resolve_constraints (model_type_map &result)
+  bool consider_lubs (model_type_map &result)
   {
-    consider_equality ();
+    bool unfound = false;
     for (std::set<model_type_variable *>::const_iterator i
 	   = formal_type_params.begin ();
 	 i != formal_type_params.end ();
@@ -526,11 +537,80 @@
 	    std::set<model_class *> constraints;
 	    update_constraint_set (LESS_THAN, *i, constraints);
 	    update_constraint_set (GREATER_THAN, *i, constraints);
-	    result.add (*i, compute_lub (constraints));
+	    model_class *lub = compute_lub (constraints);
+	    if (lub == NULL)
+	      unfound = true;
+	    else
+	      result.add (*i, lub);
 	  }
       }
+    return unfound;
   }
 
+  bool consider_return_type (model_type_map &result)
+  {
+    // Make a new type make to transform the declared return type.
+    model_type_map temp;
+    for (std::set<model_type_variable *>::const_iterator i
+	   = formal_type_params.begin ();
+	 i != formal_type_params.end ();
+	 ++i)
+      {
+	model_class *k = result.find (*i);
+	if (! k)
+	  k = *i;
+	temp.add (*i, k);
+      }
+
+    // Transform the return type.
+    // FIXME: the request element here is bogus.
+    model_class *r_class = assert_cast<model_class *> (declared_return_type);
+    model_class *r_prime = r_class->apply_type_map (declared_return_type,
+						    temp);
+
+    // Set up for the next round of type inference.
+    constraints[0].clear ();
+    constraints[1].clear ();
+    constraints[2].clear ();
+    mapping.clear ();
+
+    unify (GREATER_THAN, assign_conv_type, r_prime);
+    // FIXME: add constraints based on the bounds.  See the JLS.
+
+    consider_equality ();
+    return consider_lubs (result);
+  }
+
+  void infer_as_object (model_type_map &result)
+  {
+    model_class *obj = global->get_compiler ()->java_lang_Object ();
+    for (std::set<model_type_variable *>::const_iterator i
+	   = formal_type_params.begin ();
+	 i != formal_type_params.end ();
+	 ++i)
+      {
+	if (! result.find (*i))
+	  result.add (*i, obj);
+      }
+  }
+
+  void resolve_constraints (model_type_map &result)
+  {
+    // Look at '==' constraints.
+    consider_equality ();
+    // Look at '<<' and '>>' constraints.
+    bool any_missing = consider_lubs (result);
+    // If we are still haven't inferred all the types, do the special
+    // assignment conversion processing.
+    if (any_missing && assign_conv_type
+	&& declared_return_type->reference_p ())
+      any_missing = consider_return_type (result);
+    // If we are still haven't inferred all the types, infer them as
+    // Object.
+    if (any_missing)
+      infer_as_object (result);
+  }
+
   void get_formal_argument_types (model_method *method,
 				  std::list<model_type *> &formal)
   {
@@ -553,9 +633,22 @@
 
 public:
 
-  unifier (const location &w)
-    : where (w)
+  unifier (const location &w, model_type *drt, model_type *act)
+    : where (w),
+      declared_return_type (drt)
   {
+    // Weird logic here: if the assignment conversion type is set but
+    // is not a reference type, we just skip this part of type
+    // inference.  This is because there is no action for a constraint
+    // of the form "S >> T" where S is primitive.  On the other hand,
+    // if it is not set at all, and the declared return type is a
+    // reference type, then we use Object, per the JLS.
+    if (act)
+      assign_conv_type = dynamic_cast<model_class *> (act);
+    else if (declared_return_type && declared_return_type->reference_p ())
+      assign_conv_type = global->get_compiler ()->java_lang_Object ();
+    else
+      assign_conv_type = NULL;
   }
 
   void unify (const std::list<model_type *> &actual, model_method *method,
@@ -614,17 +707,19 @@
 void
 unify (const std::list<model_type *> &actual,
        model_method *method,
-       model_class *assignment_type,
+       model_type *declared_return_type,
+       model_type *assignment_type,
        model_type_map &result)
 {
   // FIXME: correct location.
-  unifier u (method->get_location ());
+  unifier u (method->get_location (), declared_return_type, assignment_type);
   u.unify (actual, method, result);
 }
 
 model_class *
 compute_lub (model_element *request, model_class *one, model_class *two)
 {
-  unifier u (request->get_location ());
+  // We know that the return types won't be used in this case.
+  unifier u (request->get_location (), NULL, NULL);
   return u.compute_lub (one, two);
 }


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