Skip to content
← Back

src/semantic/async_literal_candidates.ghul

1
namespace Semantic is
2
use Types.Type
3
4
// Settles which overload an asynchronous function literal with no
5
// declared return type goes to, where several share the arity.
6
//
7
// Such a literal's return type is not known until its slot is,
8
// and the slot is not known until the overload is - so the
9
// resolver cannot pick from the literal's type. What the literal
10
// does say, from its body alone, is whether it produces a value.
11
// A formal asks for one or not through its return type: a
12
// task-like carrying a result, or one carrying none. Candidates
13
// whose formal disagrees with the body are out; when exactly one
14
// remains, its formal is the return type the literal takes.
15
class ASYNC_LITERAL_CANDIDATES(
16
_innate_symbol_lookup: Lookups.InnateSymbolLookup,
17
_task_like_resolver: TASK_LIKE_RESOLVER
18
) is
19
super()
20
21
init(..) is
22
si
23
24
// The one candidate the asynchronous literals among
25
// `argument_expressions` agree on, or null: when none of the
26
// arguments is such a literal, when no candidate agrees, or
27
// when more than one does.
28
find(
29
group: Symbols.FUNCTION_GROUP,
30
argument_expressions: Collections.List[Syntax.Trees.Expressions.Expression],
31
want_instance: bool
32
) -> Symbols.Function? is
33
let literals = Collections.LIST[(index: int, produces_value: bool)]()
34
35
for (index, a) in argument_expressions |> Ghul.Pipes.index() do
36
if let literal: Syntax.Trees.Expressions.FUNCTION = a then
37
if literal.contains_let_await /\ !literal.type_expression.type? then
38
literals.add((index, !literal.is_void_async))
39
fi
40
fi
41
od
42
43
return pick(group, literals, argument_expressions.count, want_instance)
44
si
45
46
// `find` with the literals already reduced to what they say:
47
// their argument positions, and whether each body produces a
48
// value.
49
pick(
50
group: Symbols.FUNCTION_GROUP,
51
literals: Collections.List[(index: int, produces_value: bool)],
52
argument_count: int,
53
want_instance: bool
54
) -> Symbols.Function? is
55
if literals.count == 0 then
56
return null
57
fi
58
59
let result: Symbols.Function? mut = null
60
let count mut = 0
61
62
for f in group.functions do
63
if !want_instance /\ f.is_instance then
64
continue
65
fi
66
67
if !f.are_arguments_declared \/ f.arguments.count != argument_count then
68
continue
69
fi
70
71
if literals |> Ghul.Pipes.all(l => formal_asks_for_result(f.arguments[l.index]) =~ l.produces_value) then
72
result = f
73
count = count + 1
74
fi
75
od
76
77
if count == 1 then
78
return result
79
fi
80
81
return null
82
si
83
84
// Whether a formal asks its asynchronous body for a value:
85
// true for a function type returning a task-like with a
86
// result, false for one returning a task-like without, and
87
// null for a formal that is not a function type or whose
88
// return is not a task-like at all - such a formal takes no
89
// asynchronous literal, whatever the body does.
90
formal_asks_for_result(formal: Type) -> bool? is
91
if !formal.is_function \/ formal.is_action then
92
return null
93
fi
94
95
let argument_count = formal.arguments.count
96
97
if argument_count == 0 then
98
return null
99
fi
100
101
let return_type = formal.arguments[argument_count - 1]
102
103
if let void_task = _innate_symbol_lookup.get_void_task_type() then
104
if return_type.matches(void_task) then
105
return false
106
fi
107
fi
108
109
let task_like = _task_like_resolver.try_resolve(return_type)
110
111
if !task_like? then
112
return null
113
fi
114
115
return !task_like.is_void_like
116
si
117
si
118
si