@@ -92,6 +92,83 @@ lambda_method_handle(
9292 symbol_table, lambda_method_handles, lambda_handle_index);
9393}
9494
95+ class no_unique_unimplemented_method_exceptiont : public std ::exception
96+ {
97+ public:
98+ explicit no_unique_unimplemented_method_exceptiont (const std::string &s)
99+ : message(s)
100+ {
101+ }
102+ const std::string message;
103+ };
104+
105+ static optionalt<irep_idt> get_unique_abstract_method (
106+ const java_class_typet::methodst &methods,
107+ const namespacet &ns)
108+ {
109+ optionalt<irep_idt> result;
110+ for (const auto &method : methods)
111+ {
112+ const auto &mangled_name = method.get_name ();
113+ static const irep_idt equals = " equals" ;
114+ static const irep_idt hashCode = " hashCode" ;
115+ if (method.get_base_name () == equals || method.get_base_name () == hashCode)
116+ {
117+ // equals and hashCode methods can't be the implemented method of a
118+ // functional interface, even if the interface re-declares them as
119+ // abstract.
120+ continue ;
121+ }
122+ if (!ns.lookup (mangled_name).type .get_bool (ID_C_abstract))
123+ continue ;
124+ if (result.has_value () && mangled_name != *result)
125+ {
126+ throw no_unique_unimplemented_method_exceptiont (
127+ " produces a type with at least two unimplemented methods" );
128+ }
129+ result = mangled_name;
130+ }
131+ return result;
132+ }
133+
134+ static optionalt<irep_idt> get_unique_unimplemented_method (
135+ const irep_idt &interface_id,
136+ const namespacet &ns)
137+ {
138+ static const irep_idt jlo = " java::java.lang.Object" ;
139+ // Terminate recursion at Object; any other base of an interface must
140+ // itself be an interface.
141+ if (jlo == interface_id)
142+ return {};
143+
144+ const java_class_typet &interface =
145+ to_java_class_type (ns.lookup (interface_id).type );
146+
147+ if (interface.get_is_stub ())
148+ {
149+ throw no_unique_unimplemented_method_exceptiont (
150+ " produces a type that inherits the stub type " + id2string (interface_id));
151+ }
152+
153+ optionalt<irep_idt> result =
154+ get_unique_abstract_method (interface.methods (), ns);
155+
156+ for (const auto &base : interface.bases ())
157+ {
158+ optionalt<irep_idt> base_result =
159+ get_unique_unimplemented_method (base.type ().get_identifier (), ns);
160+ if (base_result.has_value () && result.has_value () && *base_result != *result)
161+ {
162+ throw no_unique_unimplemented_method_exceptiont (
163+ " produces a type with at least two unimplemented methods" );
164+ }
165+ else if (base_result.has_value ())
166+ result = base_result;
167+ }
168+
169+ return result;
170+ }
171+
95172static optionalt<irep_idt> interface_method_id (
96173 const symbol_tablet &symbol_table,
97174 const struct_tag_typet &functional_interface_tag,
@@ -100,34 +177,25 @@ static optionalt<irep_idt> interface_method_id(
100177 const messaget &log)
101178{
102179 const namespacet ns{symbol_table};
103- const java_class_typet &implemented_interface_type = [&] {
104- const symbolt &implemented_interface_symbol =
105- ns.lookup (functional_interface_tag.get_identifier ());
106- return to_java_class_type (implemented_interface_symbol.type );
107- }();
108-
109- if (implemented_interface_type.get_is_stub ())
180+ try
110181 {
111- log.debug () << " ignoring invokedynamic at " << method_identifier
112- << " address " << instruction_address
113- << " which produces a stub type "
114- << functional_interface_tag.get_identifier () << messaget::eom;
115- return {};
182+ optionalt<irep_idt> method_to_implement = get_unique_unimplemented_method (
183+ functional_interface_tag.get_identifier (), ns);
184+ if (!method_to_implement)
185+ {
186+ throw no_unique_unimplemented_method_exceptiont (
187+ " produces a type with no methods" );
188+ }
189+ return method_to_implement;
116190 }
117- else if (implemented_interface_type. methods (). size () != 1 )
191+ catch ( const no_unique_unimplemented_method_exceptiont &e )
118192 {
119- log.debug ()
120- << " ignoring invokedynamic at " << method_identifier << " address "
121- << instruction_address << " which produces type "
122- << functional_interface_tag.get_identifier ()
123- << " which should have exactly one abstract method but actually has "
124- << implemented_interface_type.methods ().size ()
125- << " . Note default methods are not supported yet."
126- << " Also note methods declared in an inherited interface are not "
127- << " supported either." << messaget::eom;
193+ log.debug () << " ignoring invokedynamic at " << method_identifier
194+ << " address " << instruction_address << " with type "
195+ << functional_interface_tag.get_identifier () << " which "
196+ << e.message << " ." << messaget::eom;
128197 return {};
129198 }
130- return implemented_interface_type.methods ().at (0 ).get_name ();
131199}
132200
133201symbolt synthetic_class_symbol (
@@ -223,23 +291,25 @@ static symbolt constructor_symbol(
223291 return constructor_symbol;
224292}
225293
226- symbolt implemented_method_symbol (
294+ static symbolt implemented_method_symbol (
227295 synthetic_methods_mapt &synthetic_methods,
228296 const symbolt &interface_method_symbol,
229- const struct_tag_typet &functional_interface_tag,
230297 const irep_idt &synthetic_class_name)
231298{
232299 const std::string implemented_method_name = [&] {
233300 std::string implemented_method_name =
234301 id2string (interface_method_symbol.name );
235- const std::string &functional_interface_tag_str =
236- id2string (functional_interface_tag. get_identifier ( ));
302+ const std::string &implemented_interface_tag_str =
303+ id2string (interface_method_symbol. type . get (ID_C_class ));
237304 INVARIANT (
238- has_prefix (implemented_method_name, functional_interface_tag_str),
305+ !implemented_interface_tag_str.empty (),
306+ " implemented method's type must specify its declaring class" );
307+ INVARIANT (
308+ has_prefix (implemented_method_name, implemented_interface_tag_str),
239309 " method names should be prefixed by their defining type" );
240310 implemented_method_name.replace (
241311 0 ,
242- functional_interface_tag_str .length (),
312+ implemented_interface_tag_str .length (),
243313 id2string (synthetic_class_name));
244314 return implemented_method_name;
245315 }();
@@ -339,7 +409,6 @@ void create_invokedynamic_synthetic_classes(
339409 symbol_table.add (implemented_method_symbol (
340410 synthetic_methods,
341411 symbol_table.lookup_ref (*interface_method_id),
342- functional_interface_tag,
343412 synthetic_class_name));
344413 symbol_table.add (synthetic_class_symbol (
345414 synthetic_class_name,
0 commit comments