Discussion:
overloads & inference
Dmitry Ivankov
2007-06-15 22:35:25 UTC
Permalink
Hi.

I've found solution to bug 1026, scenario was + ->
op_Addition as operator -> op_Addition as method (overloaded, only 2
overloads) -> fail
solution is to make + ->
op_Addition as operator -> op_Addition as overloaded operator (only 2
overloads) -> more overloads from better typed args -> ok
So to make it work I add new DelayedTyping.Kind.OverloadedOperator, which do
same things as Kind.Overloaded, but also do LookupOperator (arg.type, name).

And here goes the question: how does typing collect all possible overloads?
Does it fetch new ones when args types become more precise? (maybe extension
methods have
problem like 1026 too)

And one more: should we allow using op_Addition-like names as synonims for
"+" and others?
Currently these names are visible only when "using
class_declaring_op_Addition" and treated as functions only, not as smth like
synonims of operators.
While "+" is also visible when it is declared in one of it's args class.
Dmitry Ivankov
2007-06-15 22:56:01 UTC
Permalink
And one tricky case I've just discovered:
if we currently have only one operator overload then it's not necessary the
right one :( , maybe more will be discovered when args are typed better.
Is it possible to check that args cant be typed anymore (but not fully typed
for example) smth like Solver.RunMe_IfNothingHelps (f : void->void), and f
is "ok, let it be this overload for operator/method".
Michal Moskal
2007-06-18 06:17:33 UTC
Permalink
Hi.
I've found solution to bug 1026, scenario was + -> op_Addition as operator
-> op_Addition as method (overloaded, only 2 overloads) ->
fail
solution is to make + -> op_Addition as operator ->
op_Addition as overloaded operator (only 2 overloads) ->
more overloads from better typed args -> ok
So to make it work I add new
DelayedTyping.Kind.OverloadedOperator, which do same things
as Kind.Overloaded, but also do LookupOperator (arg.type, name).
Sounds good to me.
And here goes the question: how does typing collect all possible overloads?
Does it fetch new ones when args types become
more precise?
The operator stays suspended until the type of at least one argument
is known. Actually not even ,,known'' but suspected to be some type T.
If at that point we know also the type S of the second operand, then
we look in both T and S, otherwise we look only in T.

Clearly this is sort of a hack. We just need to use the available
information to somehow proceed with typing. It might be possible to
first try resolving operators only if both types are known, and only
after we're stuck, try to do a single argument lookup. I'm not quite
sure though, if it's worth the effort.
(maybe extension methods have problem like 1026 too)
I wouldn't think so, because there is just one type involved in name
resolution there, so we either know it, or don't.
And one more: should we allow using op_Addition-like names as synonims for
"+" and others?
Currently these names are visible only when "using
class_declaring_op_Addition" and treated as functions only, not as smth like
synonims of operators.
While "+" is also visible when it is declared in one of
it's args class.
What would be the use scenario for this feature?
--
Micha³
Dmitry Ivankov
2007-06-18 08:13:50 UTC
Permalink
Post by Michal Moskal
Clearly this is sort of a hack. We just need to use the available
information to somehow proceed with typing. It might be possible to
first try resolving operators only if both types are known, and only
after we're stuck, try to do a single argument lookup. I'm not quite
sure though, if it's worth the effort.
How to do that 'if stuck'?
I've attached current patch, I suppose that logic should in
+ | [one] when t1.Hint.IsSome || (t2 != null && t2.Hint.IsSome) => //!!!
maybe we should wait until there are both hints
+ SetKind (Kind.Resolved (one.Compile ()))
But how to do it? Something like following?
| [one] when OnlyOneHint =>
solver.PushState ();
def ok = !IsError ( try_type (one, final = false));
solver.PopState ();
when (ok)
SetKind (Kind.Resolved (one.Compile ()))
| [one] when AllHints =>
SetKind (Kind.Resolved (one.Compile ()))

Wouldn't it be too slow? (compared to having set of all possible operators
of all seen types, or to real stuck detection)
Post by Michal Moskal
Post by Dmitry Ivankov
And one more: should we allow using op_Addition-like names as synonims
for
Post by Dmitry Ivankov
"+" and others?
Currently these names are visible only when "using
class_declaring_op_Addition" and treated as functions only, not as smth
like
Post by Dmitry Ivankov
synonims of operators.
While "+" is also visible when it is declared in one of
it's args class.
What would be the use scenario for this feature?
Don't know, maybe just transform all operator-like names to operators.
Not sure if it is ok as there are different sets of these names in different
places.
Michal Moskal
2007-06-19 19:52:54 UTC
Permalink
Post by Dmitry Ivankov
Post by Michal Moskal
Clearly this is sort of a hack. We just need to use the available
information to somehow proceed with typing. It might be possible to
first try resolving operators only if both types are known, and only
after we're stuck, try to do a single argument lookup. I'm not quite
sure though, if it's worth the effort.
How to do that 'if stuck'?
I've attached current patch, I suppose that logic should in
+ | [one] when t1.Hint.IsSome || (t2 != null && t2.Hint.IsSome) => //!!!
maybe we should wait until there are both hints
+ SetKind (Kind.Resolved (one.Compile ()))
But how to do it? Something like following?
| [one] when OnlyOneHint =>
solver.PushState ();
def ok = !IsError ( try_type (one, final = false));
solver.PopState ();
when (ok)
SetKind (Kind.Resolved (one.Compile ()))
| [one] when AllHints =>
SetKind (Kind.Resolved (one.Compile ()))
Wouldn't it be too slow? (compared to having set of all possible operators
of all seen types, or to real stuck detection)
There is this Typer.BadnessAllowed thing. It is supposed to be used as
a 'stuck-detection'. The typing looks roughly as follows:

BadnessAllowed = 0
do normal typings, saving delayed typings
while BadnessAllowed < limit && there are unresolved expressions
run delayed typings, until you cannot do anything
BadnessAllowed++

It is now used not to commit ourselves to a single overload too early,
probably this logic needs to be extended.
--
Micha³
Dmitry Ivankov
2007-06-24 08:50:58 UTC
Permalink
Following breaks inference without user-defined operators:

_ = xx => match (xx) {
| (a : int, []) => a + 2 //or without :int
| (a, [x]) => (x + a) + 1
| (_, _) => 2
}

Is it expected? Shouldn't "a" from first case give type hint for second
case?

(x+a) stays unresolved with types ? and int++, while (x+a)+1 is resolved.
It can't resolve because int++ doesn't have any hint (but it has single
upper_tyvar), x hasn't any as well.

Minor hints on xx help, int*_ or _*list[int] for example.
Michal Moskal
2007-07-10 08:01:18 UTC
Permalink
Post by Dmitry Ivankov
_ = xx => match (xx) {
| (a : int, []) => a + 2 //or without :int
| (a, [x]) => (x + a) + 1
| (_, _) => 2
}
Is it expected? Shouldn't "a" from first case give type hint for second
case?
No, yes.
Post by Dmitry Ivankov
(x+a) stays unresolved with types ? and int++, while (x+a)+1 is resolved.
It can't resolve because int++ doesn't have any hint (but it has single
upper_tyvar), x hasn't any as well.
The hint should propagate in this case. If we have int :> 'a :> 'b,
then we also should have int :> 'b. I'm not quite sure why it doesn't
happen, will try to have a look today.
--
Micha³
Loading...