-
Notifications
You must be signed in to change notification settings - Fork 29
Decide slot ambiguity by the dispatch family, not by a declared name #1250
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
29ffce9
cb3c9da
01781f4
f4c03ed
de578a6
5ac3bfa
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1020,8 +1020,18 @@ private Set<String> collectDispatchSlotNames(ImClass receiverClass, List<ImMetho | |
| slotNames.add(dispatchSlotName(alias)); | ||
| } | ||
| } | ||
| // Only the method's own declared name. A specialised method's trailing segment is the | ||
| // type argument, which names no method, so composing a slot from it hands one method's | ||
| // implementation a name that belongs to nobody - and to the wrong method if some other | ||
| // method happens to be declared with that word. | ||
| String semanticName = semanticNameFromMethodName(m.getName()); | ||
| if (!semanticName.isEmpty()) { | ||
| // The same rule as the one composing the aliases: the declared name, or that name with the | ||
| // number the translation uses to tell overloads apart. An override of a numbered overload | ||
| // has to be able to replace the slot its ancestor composed. | ||
| String declared = LuaDispatchPreparation.declaredName(m); | ||
| if (!semanticName.isEmpty() && (semanticName.equals(declared) | ||
| || (!declared.isEmpty() && semanticName.startsWith(declared) | ||
| && LuaDispatchPreparation.isOverloadNumber(semanticName.substring(declared.length()))))) { | ||
|
Comment on lines
+1032
to
+1034
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When a generic base declares AGENTS.md reference: AGENTS.md:L264-L267 Useful? React with 👍 / 👎. |
||
| semanticNames.add(semanticName); | ||
| } | ||
| String sourceSemanticName = sourceSemanticName(m); | ||
|
|
@@ -1035,66 +1045,17 @@ private Set<String> collectDispatchSlotNames(ImClass receiverClass, List<ImMetho | |
| // class every method's trailing segment is the type argument, which is exactly that | ||
| // case, and the resulting slot is never called. Left uncomposed rather than bound | ||
| // arbitrarily; LuaDispatchPreparation drops the matching alias for the same reason. | ||
| Set<String> ambiguous = ambiguousSemanticNames(receiverClass); | ||
| Set<String> classNames = new TreeSet<>(); | ||
| collectClassNamesInHierarchy(receiverClass, classNames, new HashSet<>()); | ||
| for (String className : classNames) { | ||
| for (String semanticName : semanticNames) { | ||
| if (ambiguous.contains(semanticName)) { | ||
| continue; | ||
| } | ||
| slotNames.add(dispatchSlotName(className + "_" + semanticName)); | ||
| } | ||
| } | ||
| } | ||
| return slotNames; | ||
| } | ||
|
|
||
| /** | ||
| * The semantic names which name no method in particular, cached per class. | ||
| * <p> | ||
| * A method and its overrides share a semantic name and must share a slot: that is dispatch, and | ||
| * they all declare the same name in the source. The siblings of one specialisation declare | ||
| * different names and still compose the same segment, because for a specialised method that | ||
| * segment is the type argument - and the slot composed from it is claimed by whichever is bound | ||
| * first, then never called. | ||
| * <p> | ||
| * The dispatch group key would be a sharper identity but cannot be used: it embeds the signature, | ||
| * and a generic override chain's signatures differ by the type variable of each class in it | ||
| * ({@code void|T192,real} against {@code void|T636,real}), so overrides would read as unrelated | ||
| * and their shared slot would be dropped. What that leaves uncovered is recorded in backlog | ||
| * item 15: overloads of one source method inside a specialised class share a declared name, so | ||
| * their composed name is not seen as ambiguous and one dead key survives there. | ||
| * <p> | ||
| * Cached because {@code createMethods} asks twice per dispatch group and each ask would otherwise | ||
| * rebuild and sort the whole inherited method list. | ||
| */ | ||
| private final Map<ImClass, Set<String>> ambiguousSemanticNamesByClass = new LinkedHashMap<>(); | ||
|
|
||
| private Set<String> ambiguousSemanticNames(ImClass c) { | ||
| return ambiguousSemanticNamesByClass.computeIfAbsent(c, owner -> { | ||
| Map<String, Set<String>> claimants = new TreeMap<>(); | ||
| for (ImMethod m : collectMethodsInHierarchy(owner)) { | ||
| if (m == null) { | ||
| continue; | ||
| } | ||
| String semanticName = semanticNameFromMethodName(m.getName()); | ||
| if (semanticName.isEmpty()) { | ||
| continue; | ||
| } | ||
| claimants.computeIfAbsent(semanticName, name -> new TreeSet<>()) | ||
| .add(LuaDispatchPreparation.declaredName(m)); | ||
| } | ||
| Set<String> ambiguous = new TreeSet<>(); | ||
| claimants.forEach((name, keys) -> { | ||
| if (keys.size() > 1) { | ||
| ambiguous.add(name); | ||
| } | ||
| }); | ||
| return ambiguous; | ||
| }); | ||
| } | ||
|
|
||
| private void collectClassNamesInHierarchy(ImClass c, Set<String> out, Set<ImClass> visited) { | ||
| if (c == null || !visited.add(c)) { | ||
| return; | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When a generic class is specialized with a type whose emitted name is, for example,
route1, a method declaredroutesatisfies this predicate even thoughroute1is the specialization's type-argument segment rather than an overload number. If the class also declares a same-arityroute1method, both dispatch groups claim the same class-qualified slot and candidate ordering can bind calls to the unrelated implementation. The removed ambiguity scan rejected this distinct-declaration collision, so overload identity needs to be determined structurally rather than by accepting any numeric suffix.AGENTS.md reference: AGENTS.md:L327-L329
Useful? React with 👍 / 👎.