[gcjx] Patch: FYI: conversion updates
Tom Tromey
tromey@redhat.com
Fri Oct 28 20:19:00 GMT 2005
I'm checking this in on the gcjx branch.
This adds the initial (untested and incomplete) code for capture
conversion. It also adds code for the 'contains' operation, which is
needed when doing widening reference conversions where one side is a
generic type whose actual type parameters include a wildcard type.
This also came from the Classpath generics branch; I distilled a few
micro test cases which I will try to push into Jacks at some point.
Note that right now my goal is to get generics "working" in the sense
of being able to compile correct code. Then my plan is go back and
write Jacks test cases and go through the various error cases.
Tom
Index: ChangeLog
from Tom Tromey <tromey@redhat.com>
* model/wildcard.cc (contains_p): New method.
* model/wildcard.hh (model_wildcard::contains_p): Declare.
* conversions.hh (capture_conversion): Declare.
* conversions.cc (capture_conversion): New function.
(widen_instantiation): Likewise.
(widening_reference_conversion): Use widen_instantiation.
* model/class.hh (model_class::create_instance): Changed return
type.
(model_class::contains_p): Declare.
* model/class.cc (create_instance): Updated.
(contains_p): New method.
Index: conversions.cc
===================================================================
--- conversions.cc (revision 105944)
+++ conversions.cc (working copy)
@@ -177,6 +177,48 @@
return to;
}
+// This is a helper for widening_reference_conversion that understands
+// how to compare two instantiations.
+static bool
+widen_instantiation (model_class *to, model_class *from)
+{
+ assert (to->erasure () == from->erasure ());
+
+ if (! to->parameterized_p ())
+ {
+ // An assignment to the raw type is ok.
+ return true;
+ }
+ if (! from->parameterized_p ())
+ {
+ // An assignment from the raw type is not ok.
+ // FIXME: actually it is, when doing unchecked conversion.
+ // Should we do this here?
+ return false;
+ }
+
+ // Now we check 'contains' of each type argument. FIXME: we should
+ // perform capture conversion or equivalent on 'from'.
+ model_class_instance *from_i = assert_cast<model_class_instance *> (from);
+ model_class_instance *to_i = assert_cast<model_class_instance *> (to);
+ std::list<model_class *> from_args, to_args;
+ from_i->get_type_map (from_args);
+ to_i->get_type_map (to_args);
+
+ std::list<model_class *>::const_iterator from_it = from_args.begin ();
+ std::list<model_class *>::const_iterator to_it = to_args.begin ();
+ while (from_it != from_args.end ())
+ {
+ if (! (*to_it)->contains_p (*from_it))
+ return false;
+
+ ++from_it;
+ ++to_it;
+ }
+ assert (to_it == to_args.end ());
+ return true;
+}
+
bool
widening_reference_conversion (model_type *to, model_type *from)
{
@@ -230,30 +272,8 @@
if (tok->erasure () == iter->erasure ())
{
// At this point we have an assignment between two possible
- // parameterizations with the same base. Now check capture
- // conversion.
-
- // FIXME: this is probably wrong... check the spec.
- if (tok->type_variable_p ())
- result = true;
- else if (! tok->parameterized_p ())
- {
- // This is an assignment to the raw type.
- result = true;
- }
- else if (! iter->parameterized_p ())
- {
- // This is either two identical types or assignment of
- // the raw type to a wildcard type.
- // FIXME: do capture conversion here.
- // FIXME: result = tok == iter. ... ?
- result = true;
- }
- else
- {
- // FIXME: this is wrong.
- }
- // If we ended up here, we're done.
+ // parameterizations with the same base.
+ result = widen_instantiation (tok, iter);
break;
}
@@ -404,6 +424,73 @@
maybe_cast_wrap (result, actual);
}
+model_class_instance *
+capture_conversion (model_element *request, model_class_instance *inst)
+{
+ const model_parameters ¶ms = inst->get_type_parameters ();
+
+ std::list<model_class *> args, newargs;
+ inst->get_type_map (args);
+
+ std::list<ref_type_variable>::const_iterator formal_it = params.begin ();
+
+ bool any_changed = false;
+ for (std::list<model_class *>::const_iterator i = args.begin ();
+ i != args.end ();
+ ++i, ++formal_it)
+ {
+ if (! (*i)->wildcard_p ())
+ continue;
+ model_wildcard *w = assert_cast<model_wildcard *> (*i);
+ model_class *bound = w->get_bound ();
+ model_class *new_bound = NULL; // FIXME: actual bound
+
+ // Get the actual bound from the type variable.
+ std::list<model_class *> actual_bound;
+ {
+ if ((*formal_it)->get_superclass ())
+ actual_bound.push_back ((*formal_it)->get_superclass ());
+ std::list<ref_forwarding_type> &ifaces
+ = (*formal_it)->get_interfaces ();
+ for (std::list<ref_forwarding_type>::const_iterator j
+ = ifaces.begin ();
+ j != ifaces.end ();
+ ++j)
+ actual_bound.push_back (assert_cast<model_class *> ((*j)->type ()));
+ }
+
+ // FIXME: memory leak?
+ model_type_variable *newvar
+ = new model_type_variable (request->get_location ());
+
+ if (w->super_p ())
+ {
+ assert (bound);
+ // FIXME
+// newvar->set_lower_bound (bound);
+ }
+ else if (bound)
+ {
+ actual_bound.push_back (bound);
+ // FIXME: memory leak?
+ new_bound = new model_intersection_type (request->get_location (),
+ actual_bound);
+ }
+ // FIXME
+ // newvar->set_bound (new_bound);
+ newargs.push_back (newvar);
+
+ any_changed = true;
+ }
+
+ assert (formal_it == params.end ());
+
+ if (! any_changed)
+ return inst;
+
+ return inst->get_parent ()->create_instance (request, newargs);
+}
+
model_class *
box_primitive_type (model_type *in)
{
Index: model/class.hh
===================================================================
--- model/class.hh (revision 105951)
+++ model/class.hh (working copy)
@@ -522,6 +522,10 @@
bool assignable_from_p (model_type *other);
+ /// This returns true if this type contains (in the type argument
+ /// sense) the type OTHER.
+ virtual bool contains_p (model_class *other);
+
std::string to_string (const jvalue &) const
{
abort ();
@@ -610,8 +614,8 @@
/// argument types. This should only be called on a model_class,
/// not on an instance of a subclass; to apply a type map
/// composition, use apply_type_map.
- model_class *create_instance (model_element *,
- const std::list<model_class *> &);
+ model_class_instance *create_instance (model_element *,
+ const std::list<model_class *> &);
/// Ensure that this class lexically encloses class INNER.
void ensure_enclosing (model_class *inner);
Index: model/wildcard.hh
===================================================================
--- model/wildcard.hh (revision 105944)
+++ model/wildcard.hh (working copy)
@@ -87,6 +87,8 @@
bool assignable_from_p (model_type *);
+ bool contains_p (model_class *);
+
std::string get_pretty_name () const
{
return name;
Index: model/class.cc
===================================================================
--- model/class.cc (revision 105951)
+++ model/class.cc (working copy)
@@ -523,6 +523,13 @@
return widening_reference_conversion (this, other);
}
+bool
+model_class::contains_p (model_class *other)
+{
+ // Ordinary types must be identical.
+ return this == other;
+}
+
model_package *
model_class::get_package () const
{
@@ -2067,15 +2074,14 @@
return this;
}
-model_class *
+model_class_instance *
model_class::create_instance (model_element *request,
const std::list<model_class *> ¶ms)
{
model_type_map type_map;
type_parameters.create_type_map (type_map, request, params);
- if (type_parameters.empty () || type_map.empty_p ())
- return this;
+ assert (! type_parameters.empty () && ! type_map.empty_p ());
// See if this instance has been cached.
model_class_instance *cache = instance_cache.find_instance (type_map);
Index: model/wildcard.cc
===================================================================
--- model/wildcard.cc (revision 105944)
+++ model/wildcard.cc (working copy)
@@ -39,6 +39,27 @@
return k->assignable_from_p (bound->type ());
}
+bool
+model_wildcard::contains_p (model_class *other)
+{
+ if (! bound)
+ // FIXME? This is done on the theory that no bound == Object.
+ return true;
+ model_class *k = assert_cast<model_class *> (bound->type ());
+ if (other == k)
+ return true;
+ if (! other->wildcard_p ())
+ return false;
+ model_wildcard *w = assert_cast<model_wildcard *> (other);
+ // FIXME: maybe a bound is ok?
+ if (w->super_p () != is_super || ! w->get_bound ())
+ return false;
+ model_class *other_bound = w->get_bound ();
+ if (is_super)
+ return other_bound->assignable_from_p (k);
+ return k->assignable_from_p (other_bound);
+}
+
void
model_wildcard::resolve_hook (resolution_scope *scope)
{
Index: conversions.hh
===================================================================
--- conversions.hh (revision 105944)
+++ conversions.hh (working copy)
@@ -1,6 +1,6 @@
// Conversions as specified by JLS.
-// Copyright (C) 2004 Free Software Foundation, Inc.
+// Copyright (C) 2004, 2005 Free Software Foundation, Inc.
//
// This file is part of GCC.
//
@@ -63,6 +63,11 @@
void method_invocation_conversion (model_type *formal,
ref_expression &actual);
+/// This implements capture conversion as defined in the JLS.
+/// Essentially it replaces wildcards in a parameterization with new
+/// type variables.
+model_class_instance *capture_conversion (model_class_instance *);
+
/// Return the wrapper type for a given primitive type. This also
/// works for `void'. Only primitive types and void can be passed as
/// arguments.
More information about the Java-patches
mailing list