[Issue 7355] inout incorrectly resolved if the same type has both mutable and immutable parts

2022-12-17 Thread d-bugmail--- via Digitalmars-d-bugs
https://issues.dlang.org/show_bug.cgi?id=7355

Iain Buclaw  changed:

   What|Removed |Added

   Priority|P2  |P3

--


[Issue 7355] inout incorrectly resolved if the same type has both mutable and immutable parts

2012-02-03 Thread d-bugmail
http://d.puremagic.com/issues/show_bug.cgi?id=7355



--- Comment #12 from timon.g...@gmx.ch 2012-02-03 14:42:21 PST ---
(In reply to comment #11)
 (In reply to comment #10)
  For example, this should type check:
  
  immutable(int)[] arr = [2,3,4];
  inout(const(int))[] foo(inout(int)[] x){
  return uniform(0,2) ? arr : x;
  }
  inout(int)[] id(inout(int)[] x){
  return x;
  }
  inout(int)[] bar(inout(int)[] x){
  inout(int)[] y = [1,2,3];
  inout(const(int))[] z = id(foo(y)); // inout const substitute for inout
  return z~x;
  }
 
 This typechecks even if we don't have inout(const) as an option:
 [snip.]
 

My point was that it does not _if_ we have it as an option (and it has to be an
option if we want inout to be powerful enough to replace identical overloads on
const). Furthermore, foo cannot type check without inout(const) and provide the
same guarantees.

Maybe my example was not illustrative enough, second try:

immutable(int)[] arr = [2,3,4];
inout(const(int))[] foo(inout(int)[] x){
return uniform(0,2) ? arr : x;
}
inout(int)[] id(inout(int)[] x){
return x;
}
inout(const(int))[] bar(inout(int)[] x){
inout(int)[] y = [1,2,3];
return id(foo(y)); // 
}
void main(){
auto a = new int[10];
auto b = bar(a);
static assert(is(typeof(b)==const(int)[])); // !!!
auto c = new immutable(int)[10];
immutable(int)[] d = bar(c); // !!!
}

foo(y) = inout(const(int))[]
id(foo(y)) =! inout(const(int))[]// has to use inout const as inout
substitute!

resolve inout to mutable or const:
return type inout(const(int))[] = const(int)[]

resolve inout to immutable:
return type inout(const(int))[] = immutable(int)[]



 Besides, you are assuming here that the lvalue side of the expression plays a
 role in determining the inout match.  It doesn't.  The return type is solely
 determined by the argument expressions.
 

I don't see why you think I am.

  There are indeed corner cases, for example:
  
  void foo(immutable(int) x, float y){}
  void foo(const(int) x, float y){}
  void foo(int x, float y){}
  
  void main(){foo(1,1);} // error, matches all three
 
 This case has no relevance, there is no inout return value.  Who cares what
 inout resolves to?

Nobody. You claimed that the overload resolution rules are good enough to
uniquely determine what inout should resolve to in all cases, and I provided a
minimal counter-example. If you want something a little bit more concrete,
consider this:

immutable(int)[] foo(immutable(int)[] x, float f){return x;}
int[] foo(int[] x, float f){return x;}

void main(){foo([1,2,3],4);} // error

I am becoming quite confident that the overload resolution rules are the
culprit. A parameter type should be considered more specialized than another
one if it better matches the argument type. That would render the
disambiguation steps in my sketch unnecessary.

 
 Not to be nit picky, but we should consider that any polysemous value type is
 not going to play a vital role in an inout function, since it's implicitly
 convertible to any modifier.  It's references or contained references which
 make a difference.

I was making a statement about the overload resolution rules. Those also apply
to reference types.

 
 If it comes down to supporting this, choosing any inout match arbitrarily is
 good enough.

In this exact case, yes. In general, no.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
--- You are receiving this mail because: ---


[Issue 7355] inout incorrectly resolved if the same type has both mutable and immutable parts

2012-02-03 Thread d-bugmail
http://d.puremagic.com/issues/show_bug.cgi?id=7355



--- Comment #13 from Steven Schveighoffer schvei...@yahoo.com 2012-02-03 
15:46:53 PST ---
Once again you are right Timon!

I was neglecting to see in the original example that the call was id(foo(y))
instead of just id(y)!  I sometimes cannot penetrate your inadvertent
obfuscation :)  Your original example was (should have been) sufficient.

I see now that inout(const) must be a consideration for substituting inout.

Now, regarding overload resolution as it pertains to resolving what inout
means, I still think a simple algorithm as I previously stated should work.  We
just need to add inout(const) as a possible substitute.  I think the ordering
should be something like:

mutable, immutable, inout, inout(const), const

Note that inout and inout(const) are the local version (not the wildcard
version).  Also note that mutable, immutable, and inout could be in any order.

The algorithm I stated earlier needs to be modified.  The easiest way to state
it is, try each of the above substitutes for inout in order, and the first one
that type-checks, wins.  I think it works because there are no cycles in the
implicit conversion graph:

mutable +--+
|  |
immutable --+-- inout(const) -+- const 
|  |
inout --+--+

But I don't see why we need complex overload rules as you stated.  Can you show
a counter-example to my simple design?  I'd like to keep things simple, because
inout is already difficult to understand and making it simple to explain is a
huge benefit.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
--- You are receiving this mail because: ---


[Issue 7355] inout incorrectly resolved if the same type has both mutable and immutable parts

2012-02-03 Thread d-bugmail
http://d.puremagic.com/issues/show_bug.cgi?id=7355



--- Comment #14 from Steven Schveighoffer schvei...@yahoo.com 2012-02-03 
15:59:19 PST ---
Er... messed up that graph a smidge

(In reply to comment #13)
 mutable ---+
|
 immutable --+-- inout(const) -+- const 
 |  |
 inout --+--+

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
--- You are receiving this mail because: ---


[Issue 7355] inout incorrectly resolved if the same type has both mutable and immutable parts

2012-02-03 Thread d-bugmail
http://d.puremagic.com/issues/show_bug.cgi?id=7355



--- Comment #16 from timon.g...@gmx.ch 2012-02-03 16:26:32 PST ---
(In reply to comment #13)
 Once again you are right Timon!
 
 I was neglecting to see in the original example that the call was id(foo(y))
 instead of just id(y)!  I sometimes cannot penetrate your inadvertent
 obfuscation :)  Your original example was (should have been) sufficient.
 

OK. What measures can I take to less obfuscate my code? =)

 I see now that inout(const) must be a consideration for substituting inout.
 
 Now, regarding overload resolution as it pertains to resolving what inout
 means, I still think a simple algorithm as I previously stated should work.  
 We
 just need to add inout(const) as a possible substitute.  I think the ordering
 should be something like:
 
 mutable, immutable, inout, inout(const), const
 
 Note that inout and inout(const) are the local version (not the wildcard
 version).  Also note that mutable, immutable, and inout could be in any order.
 
 The algorithm I stated earlier needs to be modified.  The easiest way to state
 it is, try each of the above substitutes for inout in order, and the first one
 that type-checks, wins.  I think it works because there are no cycles in the
 implicit conversion graph:
 
 mutable ---+
|
 immutable --+-- inout(const) -+- const 
 |  |
 inout --+--+
 
 But I don't see why we need complex overload rules as you stated.  Can you 
 show a counter-example to my simple design? 

I think what you propose would work.

But the overload rule I want to add (see issue 7431) is actually quite
intuitive and I think it is a good move to make the overload rules consistent
enough so that we could re-use them for inout matching. It benefits code that
does not use inout too.

Not fixing the overload rules would result in inout being _more_ powerful than
three overloads = inout could not be replaced by three overloads
transparently, if it was later determined that the different const versions
need different function bodies.

immutable(int)[] foo(immutable(int)[] x,float){return x;}
const(int)[] foo(const(int)[] x, float){return x;}
int[] foo(int[] x,float){return x;}

inout(int)[] bar(inout(int)[] x,float){return x;}

void main(){
foo([1,2,3],4); // would not work
bar([1,2,3],4); // would work!
}


 I'd like to keep things simple, because
 inout is already difficult to understand and making it simple to explain is a
 huge benefit.

I think 'create pseudo-overloads and use the rules for overloading' is simplest
(with the additional overloading rule, so that it works), but what you propose
should work too. The only difference between using the repaired overload
resolution and your proposal I can see is that yours introduces possible
disambiguation in the case of multiple alias this. I don't know if this is good
or bad (my initial proposal had the same characteristic).

inout(int)[] foo(inout(int)[] x){return x;}

class C{
int[] x(){writeln(x!);return new int[10];}
immutable int[] y(){writeln(y!);return new immutable(int)[10];}
alias x this;
alias y this;
}

void main(){
C c = new C;
foo(c); // should this work or fail?
}

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
--- You are receiving this mail because: ---


[Issue 7355] inout incorrectly resolved if the same type has both mutable and immutable parts

2012-02-03 Thread d-bugmail
http://d.puremagic.com/issues/show_bug.cgi?id=7355



--- Comment #17 from Steven Schveighoffer schvei...@yahoo.com 2012-02-03 
16:54:12 PST ---
(In reply to comment #16)
 (In reply to comment #13)
  Once again you are right Timon!
  
  I was neglecting to see in the original example that the call was id(foo(y))
  instead of just id(y)!  I sometimes cannot penetrate your inadvertent
  obfuscation :)  Your original example was (should have been) sufficient.
  
 
 OK. What measures can I take to less obfuscate my code? =)

hehe, use temporaries to demonstrate what types should be.  Or more inline
comments maybe.  I just missed seeing the double call in one expression.

For example, this could have been more effective:

// your definition for foo

inout(int)[] id(inout(int)[] x) { return x;}

inout(const(int))[] bar(inout(int)[] x)
{
   inout(const(int))[] tmp = foo(x);
   return id(tmp); // need to be able to call
}

 I think what you propose would work.
 
 But the overload rule I want to add (see issue 7431) is actually quite
 intuitive and I think it is a good move to make the overload rules consistent
 enough so that we could re-use them for inout matching. It benefits code that
 does not use inout too.
 
 Not fixing the overload rules would result in inout being _more_ powerful than
 three overloads = inout could not be replaced by three overloads
 transparently, if it was later determined that the different const versions
 need different function bodies.

inout is *already* more powerful.  It guarantees no molestation, even for
mutable args.

But I see your point.  I'm not opposed to fixing both, but this way of
explaining inout is simple to me, and to someone who doesn't want to get into
the complexities of understanding overload resolution.  In other words, one
doesn't have to be able to understand overload resolution to understand inout.

Consequently, if the way it gets implemented is that overload resolution is
fixed, and then inout uses that, it's not any different, but it's easier to
explain this way (IMO).

 The only difference between using the repaired overload
 resolution and your proposal I can see is that yours introduces possible
 disambiguation in the case of multiple alias this. I don't know if this is 
 good
 or bad (my initial proposal had the same characteristic).
 
 inout(int)[] foo(inout(int)[] x){return x;}
 
 class C{
 int[] x(){writeln(x!);return new int[10];}
 immutable int[] y(){writeln(y!);return new immutable(int)[10];}
 alias x this;
 alias y this;
 }
 
 void main(){
 C c = new C;
 foo(c); // should this work or fail?
 }

I think you give me too many headaches :)  My gut says this should fail,
because the call is not just ambiguously typed, but what you *pass* to the call
is ambiguous.  Consider this less benign example:

struct S
{
   int[] x;
   immutable(int)[] y;
   alias x this;
   alias y this;
}

x and y are not just generated temporaries, so the data you pass could be
different depending on the compiler choice of what order to try the first three
type constructors.

My rules depend on the assumption that the argument type is already decided. 
In the case of literals, that's ok, because an arbitrary choice doesn't change
code paths, just the type of the expression.

In this case, we have to cry ambiguity, and fail to compile, in the name of
consistency.  So how to amend my algorithm?  I suppose something like:

try at a minimum immutable, mutable, and inout.  If more than one of these
typechecks, the call is ambiguous.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
--- You are receiving this mail because: ---


[Issue 7355] inout incorrectly resolved if the same type has both mutable and immutable parts

2012-02-03 Thread d-bugmail
http://d.puremagic.com/issues/show_bug.cgi?id=7355



--- Comment #18 from timon.g...@gmx.ch 2012-02-03 17:14:50 PST ---
(In reply to comment #17)
 (In reply to comment #16)
  (In reply to comment #13)
   Once again you are right Timon!
   
   I was neglecting to see in the original example that the call was 
   id(foo(y))
   instead of just id(y)!  I sometimes cannot penetrate your inadvertent
   obfuscation :)  Your original example was (should have been) sufficient.
   
  
  OK. What measures can I take to less obfuscate my code? =)
 
 hehe, use temporaries to demonstrate what types should be.  Or more inline
 comments maybe.  I just missed seeing the double call in one expression.
 
 For example, this could have been more effective:
 
 // your definition for foo
 
 inout(int)[] id(inout(int)[] x) { return x;}
 
 inout(const(int))[] bar(inout(int)[] x)
 {
inout(const(int))[] tmp = foo(x);
return id(tmp); // need to be able to call
 }
 
  I think what you propose would work.
  
  But the overload rule I want to add (see issue 7431) is actually quite
  intuitive and I think it is a good move to make the overload rules 
  consistent
  enough so that we could re-use them for inout matching. It benefits code 
  that
  does not use inout too.
  
  Not fixing the overload rules would result in inout being _more_ powerful 
  than
  three overloads = inout could not be replaced by three overloads
  transparently, if it was later determined that the different const versions
  need different function bodies.
 
 inout is *already* more powerful.  It guarantees no molestation, even for
 mutable args.
 

Indeed, it gives the same guarantees as const.

 But I see your point.  I'm not opposed to fixing both, but this way of
 explaining inout is simple to me, and to someone who doesn't want to get into
 the complexities of understanding overload resolution.  In other words, one
 doesn't have to be able to understand overload resolution to understand inout.
 

One goal of overload resolution is to be as intuitive as possible. Few
programmers who use overloading are actually intimately familiar with the rules
that govern the resolution process.

 Consequently, if the way it gets implemented is that overload resolution is
 fixed, and then inout uses that, it's not any different, but it's easier to
 explain this way (IMO).
 

That is probably true.

  The only difference between using the repaired overload
  resolution and your proposal I can see is that yours introduces possible
  disambiguation in the case of multiple alias this. I don't know if this is 
  good
  or bad (my initial proposal had the same characteristic).
  
  inout(int)[] foo(inout(int)[] x){return x;}
  
  class C{
  int[] x(){writeln(x!);return new int[10];}
  immutable int[] y(){writeln(y!);return new immutable(int)[10];}
  alias x this;
  alias y this;
  }
  
  void main(){
  C c = new C;
  foo(c); // should this work or fail?
  }
 
 I think you give me too many headaches :)  My gut says this should fail,
 because the call is not just ambiguously typed, but what you *pass* to the 
 call
 is ambiguous.  Consider this less benign example:
 
 struct S
 {
int[] x;
immutable(int)[] y;
alias x this;
alias y this;
 }
 
 x and y are not just generated temporaries, so the data you pass could be
 different depending on the compiler choice of what order to try the first 
 three
 type constructors.
 
 My rules depend on the assumption that the argument type is already decided. 
 In the case of literals, that's ok, because an arbitrary choice doesn't change
 code paths, just the type of the expression.
 
 In this case, we have to cry ambiguity, and fail to compile, in the name of
 consistency.  So how to amend my algorithm?  I suppose something like:
 
 try at a minimum immutable, mutable, and inout.  If more than one of these
 typechecks, the call is ambiguous.

What if one is a better match than the other? If it should fail I think we
should use the repaired overload resolution. It has exactly the required
semantics.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
--- You are receiving this mail because: ---


[Issue 7355] inout incorrectly resolved if the same type has both mutable and immutable parts

2012-02-02 Thread d-bugmail
http://d.puremagic.com/issues/show_bug.cgi?id=7355



--- Comment #9 from Steven Schveighoffer schvei...@yahoo.com 2012-02-02 
12:07:29 PST ---
(In reply to comment #8)
 This rule should work satisfactory:
 
 - The compiler is required to resolve inout such that the behavior is as if
 there were four (five, with inout(const(T)) enhancement in place) separate
 overloads. This could be implemented similar to how you propose it, by adding
 all of the versions to the overload set, or by using some insights to speed up
 the process (not very hard)

This sounds fine.  However, inout(const(T)) is not a substitute for inout(T),
so it should be four.

inout(const(T)) is special in what can implicitly convert to it.  But the inout
is the only wildcard there.

The rest is not necessary.  The normal overload rules already should handle
which one is chosen.  Since inout, mutable, and immutable do not implicitly
convert to each other, it's not possible for there to be an ambiguity, is
there?  immutable and mutable (and by extension inout) should be preferred over
const.

It's important to note that the inout overload we are talking about is not the
wildcard inout, but the local const-like inout.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
--- You are receiving this mail because: ---


[Issue 7355] inout incorrectly resolved if the same type has both mutable and immutable parts

2012-02-02 Thread d-bugmail
http://d.puremagic.com/issues/show_bug.cgi?id=7355



--- Comment #10 from timon.g...@gmx.ch 2012-02-02 13:05:31 PST ---
(In reply to comment #9)
 (In reply to comment #8)
  This rule should work satisfactory:
  
  - The compiler is required to resolve inout such that the behavior is as if
  there were four (five, with inout(const(T)) enhancement in place) separate
  overloads. This could be implemented similar to how you propose it, by 
  adding
  all of the versions to the overload set, or by using some insights to speed 
  up
  the process (not very hard)
 
 This sounds fine.  However, inout(const(T)) is not a substitute for inout(T),
 so it should be four.
 

inout(const(T)) should be its own type. And as soon as that is the case, inout
const will have to be a valid substitute for inout.

For example, this should type check:

immutable(int)[] arr = [2,3,4];
inout(const(int))[] foo(inout(int)[] x){
return uniform(0,2) ? arr : x;
}
inout(int)[] id(inout(int)[] x){
return x;
}
inout(int)[] bar(inout(int)[] x){
inout(int)[] y = [1,2,3];
inout(const(int))[] z = id(foo(y)); // inout const substitute for inout
return z~x;
}


 inout(const(T)) is special in what can implicitly convert to it.  But the 
 inout
 is the only wildcard there.

True, but that does not mean it should not be a valid substitute for inout. 

 
 The rest is not necessary.  The normal overload rules already should handle
 which one is chosen.  Since inout, mutable, and immutable do not implicitly
 convert to each other, it's not possible for there to be an ambiguity, is
 there?  immutable and mutable (and by extension inout) should be preferred 
 over
 const.

There are indeed corner cases, for example:

void foo(immutable(int) x, float y){}
void foo(const(int) x, float y){}
void foo(int x, float y){}

void main(){foo(1,1);} // error, matches all three

A different solution would be to refine the overload rules.


 
 It's important to note that the inout overload we are talking about is not the
 wildcard inout, but the local const-like inout.

Exactly. The same holds for inout(const(T)).

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
--- You are receiving this mail because: ---


[Issue 7355] inout incorrectly resolved if the same type has both mutable and immutable parts

2012-01-27 Thread d-bugmail
http://d.puremagic.com/issues/show_bug.cgi?id=7355



--- Comment #8 from timon.g...@gmx.ch 2012-01-27 14:44:19 PST ---
This rule should work satisfactory:

- The compiler is required to resolve inout such that the behavior is as if
there were four (five, with inout(const(T)) enhancement in place) separate
overloads. This could be implemented similar to how you propose it, by adding
all of the versions to the overload set, or by using some insights to speed up
the process (not very hard)

- If there would be an ambiguity between the different pseudo overloads:
-- If one of the remaining multiple possibilities is the const version, drop it
-- If one of the possibilities is the inout version, drop it
(-- If one of the remaining multiple possibilities is the inout const version,
drop it)
-- If mutable and immutable are remaining possible matches for inout, resolve
inout to mutable.
-- otherwise resolve inout to what is left.

- Allow direct conversion of the return type to any of the versions of inout
that still match after implicit conversions of the arguments in place.

- An inout function is considered to be less specialized than a corresponding
non-inout one.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
--- You are receiving this mail because: ---


[Issue 7355] inout incorrectly resolved if the same type has both mutable and immutable parts

2012-01-26 Thread d-bugmail
http://d.puremagic.com/issues/show_bug.cgi?id=7355



--- Comment #1 from Kenji Hara k.hara...@gmail.com 2012-01-26 04:30:30 PST ---
My understanding is, each inout deduction from a function argument just like
pattern matching.

Parameter type:   inout(  int *)*
 Argument type: mutable(immutable(int)*)*  // mutable(...) is pseudo modifier
-- 'inout' is deduced to 'mutable'.

I think if we allow this kind of deduction, there is an ambiguous case:

inout(int) foo(inout(int**) x){ return 0; }
void main()
{
immutable(int*)* x;
foo(x);
// inout is deduced to imuutable or const? Both conversions
//  immutable(int*)* to immutable(int**)
//  immutable(int*)* to const(int**)
// are valid, so it is ambiguous.
}

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
--- You are receiving this mail because: ---


[Issue 7355] inout incorrectly resolved if the same type has both mutable and immutable parts

2012-01-26 Thread d-bugmail
http://d.puremagic.com/issues/show_bug.cgi?id=7355


Steven Schveighoffer schvei...@yahoo.com changed:

   What|Removed |Added

 CC||schvei...@yahoo.com


--- Comment #2 from Steven Schveighoffer schvei...@yahoo.com 2012-01-26 
07:56:53 PST ---
(In reply to comment #1)
 My understanding is, each inout deduction from a function argument just like
 pattern matching.
 
 Parameter type:   inout(  int *)*
  Argument type: mutable(immutable(int)*)*  // mutable(...) is pseudo modifier
 -- 'inout' is deduced to 'mutable'.

The compiler should either fail to match, since inout wildcard is not applying
to the immutable, or if it does match, it should treat foo as:

int** foo(int **x) { return x; }

This should fail to be able to be called with immutable(int)**.

The assert should fail because the typeof should resolve to Error.

I think this bug is invalid.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
--- You are receiving this mail because: ---


[Issue 7355] inout incorrectly resolved if the same type has both mutable and immutable parts

2012-01-26 Thread d-bugmail
http://d.puremagic.com/issues/show_bug.cgi?id=7355



--- Comment #3 from timon.g...@gmx.ch 2012-01-26 09:07:23 PST ---
(In reply to comment #2)
 (In reply to comment #1)
  My understanding is, each inout deduction from a function argument just like
  pattern matching.
  
  Parameter type:   inout(  int *)*
   Argument type: mutable(immutable(int)*)*  // mutable(...) is pseudo 
  modifier
  -- 'inout' is deduced to 'mutable'.
 
 The compiler should either fail to match, since inout wildcard is not applying
 to the immutable, or if it does match, it should treat foo as:
 
 int** foo(int **x) { return x; }
 
 This should fail to be able to be called with immutable(int)**.
 
 The assert should fail because the typeof should resolve to Error.
 
 I think this bug is invalid.

The typeof resolves to error because inout resolves to immutable.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
--- You are receiving this mail because: ---


[Issue 7355] inout incorrectly resolved if the same type has both mutable and immutable parts

2012-01-26 Thread d-bugmail
http://d.puremagic.com/issues/show_bug.cgi?id=7355



--- Comment #4 from timon.g...@gmx.ch 2012-01-26 09:20:32 PST ---
(In reply to comment #1)
 My understanding is, each inout deduction from a function argument just like
 pattern matching.
 
 Parameter type:   inout(  int *)*
  Argument type: mutable(immutable(int)*)*  // mutable(...) is pseudo modifier
 -- 'inout' is deduced to 'mutable'.


The compiler deduces inout to _immutable_ in this case. Other than that, it
does not make much sense to talk about a mutable pseudo modifier: inout is
transitive, but such a pseudo modifier cannot be transitive.

 I think if we allow this kind of deduction, there is an ambiguous case:
 
 inout(int) foo(inout(int**) x){ return 0; }
 void main()
 {
 immutable(int*)* x;
 foo(x);
 // inout is deduced to imuutable or const? Both conversions
 //  immutable(int*)* to immutable(int**)
 //  immutable(int*)* to const(int**)
 // are valid, so it is ambiguous.
 }

The same ambiguity is already resolved at other points in the compiler:

inout(int) foo(inout(int) x, inout(int)* y){ return 0; }

void main(){
immutable(int)* y;
foo(1, y);
}

inout is resolved to const, even though immutable would be a far better choice.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
--- You are receiving this mail because: ---


[Issue 7355] inout incorrectly resolved if the same type has both mutable and immutable parts

2012-01-26 Thread d-bugmail
http://d.puremagic.com/issues/show_bug.cgi?id=7355



--- Comment #5 from Steven Schveighoffer schvei...@yahoo.com 2012-01-26 
09:36:01 PST ---
(In reply to comment #3)

 The typeof resolves to error because inout resolves to immutable.

As I said, it should fail to match or match mutable and fail to call.  I'm not
sure which is correct, but I feel either way that the assert should fail.  If
it's resolving to immutable, I think it's a bug, not because it's not passing,
but because it's failing for the wrong reason.

I think your expectations would be a violation of const.  Let's assume inout
did resolve to const for foo, and the function could be called:

immutable int x = 5;
immutable(int)* xp = x;
immutable(int)** xpp = xp;

const(int *)* y = foo(xpp);

int z = 2;

*y = z; // this should pass, since I can assign int* to const(int*).

assert(*xp == 2);
z = 3;
assert(*xp == 3); // oops!  changed data perceived as immutable!

Is there an error in my example?  I think it comes down to this:

immutable(int *)* foo(immutable(int *)* x) // inout == immutable
const(int *)* foo(const(int *)* x) // inout == const
  int **  foo(  int **  x) // inout == mutable

none of these can be called with immutable(int)** because there is no implicit
cast to the parameter.  I don't think const(immutable(int)*)* reduces to
const(int *)*.

This does take some mental effort, so I may have made a mistake :)  I hate
double pointers...

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
--- You are receiving this mail because: ---


[Issue 7355] inout incorrectly resolved if the same type has both mutable and immutable parts

2012-01-26 Thread d-bugmail
http://d.puremagic.com/issues/show_bug.cgi?id=7355



--- Comment #6 from timon.g...@gmx.ch 2012-01-26 09:55:37 PST ---
(In reply to comment #5)
 (In reply to comment #3)
 
  The typeof resolves to error because inout resolves to immutable.
 
 As I said, it should fail to match or match mutable and fail to call.  I'm not
 sure which is correct, but I feel either way that the assert should fail.  If
 it's resolving to immutable, I think it's a bug, not because it's not passing,
 but because it's failing for the wrong reason.
 
 I think your expectations would be a violation of const. 

No.

 Let's assume inout
 did resolve to const for foo, and the function could be called:
 
 immutable int x = 5;
 immutable(int)* xp = x;
 immutable(int)** xpp = xp;
 
 const(int *)* y = foo(xpp);
 
 int z = 2;
 
 *y = z; // this should pass, since I can assign int* to const(int*).

You cannot assign anything to const(int*), that is the point of const.


 
 assert(*xp == 2);
 z = 3;
 assert(*xp == 3); // oops!  changed data perceived as immutable!
 
 Is there an error in my example?  I think it comes down to this:
 
 immutable(int *)* foo(immutable(int *)* x) // inout == immutable
 const(int *)* foo(const(int *)* x) // inout == const
   int **  foo(  int **  x) // inout == mutable
 
 none of these can be called with immutable(int)** because there is no implicit
 cast to the parameter.  I don't think const(immutable(int)*)* reduces to
 const(int *)*.

It does. The second version is callable with immutable(int)**. Not fixing this
would mean there are cases where code duplication is more expressive than
inout.

 
 This does take some mental effort, so I may have made a mistake :)  I hate
 double pointers...

We have:

immutable(T) is a subtype of const(T).

= immutable(int) : const(int)

const(T*) : const(S*) iff const(T) : const(S)

= const(immutable(int)*) : const(int*)

const(T)* : const(S)* iff const(T) : const(S)

= const(immutable(int)*)* : const(int*)*

qed

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
--- You are receiving this mail because: ---


[Issue 7355] inout incorrectly resolved if the same type has both mutable and immutable parts

2012-01-26 Thread d-bugmail
http://d.puremagic.com/issues/show_bug.cgi?id=7355



--- Comment #7 from Steven Schveighoffer schvei...@yahoo.com 2012-01-26 
10:21:28 PST ---
(In reply to comment #6)
 (In reply to comment #5)
  Let's assume inout
  did resolve to const for foo, and the function could be called:
  
  immutable int x = 5;
  immutable(int)* xp = x;
  immutable(int)** xpp = xp;
  
  const(int *)* y = foo(xpp);
  
  int z = 2;
  
  *y = z; // this should pass, since I can assign int* to const(int*).
 
 You cannot assign anything to const(int*), that is the point of const.

Oh yeah :)  Stupid me, for some reason in my head this made sense because there
was a mutable part.

  
  immutable(int *)* foo(immutable(int *)* x) // inout == immutable
  const(int *)* foo(const(int *)* x) // inout == const
int **  foo(  int **  x) // inout == mutable
  
  none of these can be called with immutable(int)** because there is no 
  implicit
  cast to the parameter.  I don't think const(immutable(int)*)* reduces to
  const(int *)*.
 
 It does. The second version is callable with immutable(int)**. Not fixing this
 would mean there are cases where code duplication is more expressive than
 inout.

You are right.  So we need to come up with some rules for inout as to how it
matches.

What about this idea?

for each inout parameter, we try as a substitute in order: mutable, immutable,
inout, const.  See if the argument can be implicitly converted to the
substituted parameter.

If none of the possible substitutes can be implicitly converted to for a single
parameter, the function fails to be called, and an error is generated inout
cannot be resolved [for parameter x]

If substitutes can be found for all of the inout parameters, and they all match
(i.e. all mutable, all immutable, all inout or all const), then that is used as
the substitute and the function is called.

If substitutes are different (e.g. one is mutable, but another is immutable),
then const is used as the substitute.  The parameters are then re-checked to
see that they all implicitly convert to the substituted const type.  If this is
not possible, an error is generated common inout substitute cannot be found.

I think this should be as capable as duplicate functions.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
--- You are receiving this mail because: ---