Skip to content

Compiler does not add type parameter in recursive inline function call, but sets it to Nothing #16599

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

Closed
hmf opened this issue Dec 29, 2022 · 1 comment

Comments

@hmf
Copy link

hmf commented Dec 29, 2022

Compiler version

Versions 3.2.1, 3.2.1-RC2 and 3.2.0

Minimized code

Code is available in scastie. This may be related to #16596.

import scala.compiletime.ops.int

type Count0[N,T] <: Tuple = (N,T) match
  case (0,_)      => EmptyTuple
  case (N,String)      => String *: Count0[int.-[N, 1], String]
  case (N,Int)         => Int *: Count0[int.-[N, 1], Int]
  case (N,Float)       => Float *: Count0[int.-[N, 1], Float]  
  case (N,Double)      => Double *: Count0[int.-[N, 1], Double]  


type Count1[N,T] <: Tuple = (N,T) match
  case (0,T)      => EmptyTuple
  case (N,String)      => String *: Count1[int.-[N, 1], String]
  case (N,Int)         => Int *: Count1[int.-[N, 1], Int]
  case (N,Float)       => Float *: Count1[int.-[N, 1], Float]  
  case (N,Double)      => Double *: Count1[int.-[N, 1], Double]  

transparent inline def replicateT2Fail[T](n:Int): Count1[n.type,T] =
  inline if n == 0
  then
    EmptyTuple.asInstanceOf[Count1[n.type,T]]
  else
    inline val next = n - 1    
    // Fails, T made explicit
    val tail = replicateT2Fail[T](next)
    val acc = Int *: tail
    acc.asInstanceOf[Count1[n.type,T]]


transparent inline def replicateT2Ok[T](n:Int): Count1[n.type,T] =
  inline if n == 0
  then
    EmptyTuple.asInstanceOf[Count1[n.type,T]]
  else
     // val tail = replicate(n-1)
    inline val next = n - 1
    // OK, T' == Nothing?
    val tail = replicateT2Ok(next)
    val acc = Int *: tail
    acc.asInstanceOf[Count1[n.type,T]]

val rep1Tc = replicateT2Ok[Int](3)
//summon[rep1Tc.type <:< Int *: Int *: Int *: EmptyTuple] 
println(rep1Tc)

val rep1Td = replicateT2Fail[Int](3)
//summon[rep1Td.type <:< Int *: Int *: Int *: EmptyTuple] 
println(rep1Td)

Note: when compiling with 3.2.1 the commented summons above compile, but in Scastie, it fails to compile.

Output

    Found:    (Int, Int)
    Required: Int *: Playground.Count1[(next : (2 : Int)) - (1 : Int), Int]

    Found:    Int.type *: Int *: Int *: Playground.Count1[(1 : Int) - (1 : Int), Int]
    Required: Int.type *: Int *: Playground.Count1[(next : (2 : Int)) - (1 : Int), Int]

Expectation

As described in #16596, if Count1[N,T] fails for N > 2, I would expect any function that uses this match type, to fail also. Strangely enough, it doesn't.

In the example above, replicateT2Ok[T](n:Int) I do not set [T] explicitly in the recursive call. I would expect this to be set to to T. However, it seems like it s set to Nothing, hence making Count1[N,T] and Count0[N,T] have the same final case. I don't know why, but compilation succeeds.

In the example above, replicateT2Fail[T](n:Int) I set [T] explicitly in the recursive call. As expected, I get a compilation error. This error seems to be the one I get in #16596, as is expected. What I do not expect, is to have to set T explicitly in the recursive call. I assumed the compiler would do it automatically.

@hmf hmf added itype:bug stat:needs triage Every issue needs to have an "area" and "itype" label labels Dec 29, 2022
@prolativ
Copy link
Contributor

The problem with summon[rep1Tc.type <:< Int *: Int *: Int *: EmptyTuple] in scastie is because your snippet uses scala 3.2.1-RC2 and this problem got already fixed in 3.2.1.

The fact that replicateT2Ok is called recursively indeed does not influence how the type parameter is inferred and this is as designed. What is taken into account when inferring type parameters of a method call are the types of term (value) parameters and the expected return type. Having none of these clues the compiler infers Nothing.

Taking the above into account, this issue seems to reduce to a duplicate of #16596

@prolativ prolativ closed this as not planned Won't fix, can't repro, duplicate, stale Dec 30, 2022
@prolativ prolativ added stat:duplicate and removed stat:needs triage Every issue needs to have an "area" and "itype" label labels Dec 30, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants