This is the mail archive of the
java-patches@gcc.gnu.org
mailing list for the Java project.
[gcjx] Patch: FYI: more type inference work
- From: Tom Tromey <tromey at redhat dot com>
- To: Java Patch List <java-patches at gcc dot gnu dot org>
- Date: 09 Nov 2005 15:31:20 -0700
- Subject: [gcjx] Patch: FYI: more type inference work
- Reply-to: tromey at redhat dot com
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);
}