Skip to content
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

Argument types are erroneously inferred as Nothing when a method is explicitly eta-expanded as in f(_) #16405

Closed
neko-kai opened this issue Nov 23, 2022 · 1 comment · Fixed by #16625 or #16764

Comments

@neko-kai
Copy link
Contributor

Compiler version

3.2.1 and 3.2.2-RC1

Minimized code

Runnable: https://scastie.scala-lang.org/WNexehduQzOT4XJ2XfUB7Q

import scala.compiletime.summonInline

case class TypeDesc[T](tpe: String)
object TypeDesc {
  given TypeDesc[Nothing] = TypeDesc("Nothing")
  given TypeDesc[String] = TypeDesc("String")
  given TypeDesc[Int] = TypeDesc("Int")
}

def exampleFn(s: String, i: Int): Unit = ()

inline def argumentTypesOf[R](fun: (?, ?) => R): (TypeDesc[?], TypeDesc[?]) = {
  inline fun match {
    case x: ((a, b) => R) =>
      (summonInline[TypeDesc[a]], summonInline[TypeDesc[b]])
  }
}

inline def argumentTypesOfNoWildCard[A, B, R](fun: (A, B) => R): (TypeDesc[?], TypeDesc[?]) = argumentTypesOf(fun)

inline def argumentTypesOfAllWildCard(fun: (?, ?) => ?): (TypeDesc[?], TypeDesc[?]) = argumentTypesOf(fun)

@main def main: Unit = {
  println(argumentTypesOf(exampleFn)) // good
  println(argumentTypesOf(exampleFn(_, _))) // bad
  println(argumentTypesOfNoWildCard(exampleFn(_, _))) // good
  println(argumentTypesOfAllWildCard(exampleFn)) // bad, even without explicit placeholders
}

Output

(TypeDesc(String),TypeDesc(Int))
(TypeDesc(Nothing),TypeDesc(Nothing))
(TypeDesc(String),TypeDesc(Int))
(TypeDesc(Nothing),TypeDesc(Nothing))

Expectation

(TypeDesc(String),TypeDesc(Int))
(TypeDesc(String),TypeDesc(Int))
(TypeDesc(String),TypeDesc(Int))
(TypeDesc(String),TypeDesc(Int))

Expected there to be no difference between exampleFn and exampleFn(_, _) form in type inference in general and when calling argumentTypesOf.
Expected all variants of argumentTypesOf* to not infer Nothing regardless of using wildcards anywhere in the parameter type.

This code is a minimized version of real library code in https://github.com/izumi/izumi which we're trying to port to Scala 3

@neko-kai neko-kai added itype:bug stat:needs triage Every issue needs to have an "area" and "itype" label labels Nov 23, 2022
@neko-kai neko-kai changed the title Argument types are erroneously inferred as Nothing when a method explicitly eta-expanded using placeholders as in f(_) Argument types are erroneously inferred as Nothing when a method is explicitly eta-expanded as in f(_) Nov 23, 2022
@szymon-rd szymon-rd added area:typer area:inline and removed stat:needs triage Every issue needs to have an "area" and "itype" label labels Nov 24, 2022
@szymon-rd
Copy link
Contributor

szymon-rd commented Nov 25, 2022

Thank you for reporting and minimization!

@Kordyjan Kordyjan added this to the Future versions milestone Dec 12, 2022
@jchyb jchyb self-assigned this Dec 21, 2022
jchyb added a commit to jchyb/dotty that referenced this issue Jan 5, 2023
This was a problem because it could it get in the way of some
metaprogramming techniques. The main issue was the fact that when typing
functions, the type inference would first look at the types from the
source method (resolving type wildcards to Nothing) and only after that,
it could look at the target method.
Now, in the case of wildcards we delay the resolution
from the source method until later, after which it is resolved according
to the target method. We also modify the targettype resolution method
a bit, as just applying the above procedure would fail some of the
tests, eg. val y1: Function1[_, Nothing] = x => x
would be typed as Function1[Any, Nothing], which was incorrect.
jchyb added a commit to jchyb/dotty that referenced this issue Jan 5, 2023
This was a problem because it could it get in the way of some
metaprogramming techniques. The main issue was the fact that when typing
functions, the type inference would first look at the types from the
source method (resolving type wildcards to Nothing) and only after that,
it could look at the target method.
Now, in the case of wildcards we delay the resolution
from the source method until later, after which it is resolved according
to the target method. We also modify the target type resolution method
a bit, as just applying the above procedure would fail some of the
tests, eg. val y1: Function1[_, Nothing] = x => x
would be typed as Function1[Any, Nothing], which was incorrect.
jchyb added a commit to jchyb/dotty that referenced this issue Jan 9, 2023
This was a problem because it could it get in the way of some
metaprogramming techniques. The main issue was the fact that when typing
functions, the type inference would first look at the types from the
source method (resolving type wildcards to Nothing) and only after that,
it could look at the target method.
Now, in the case of wildcards we save that fact for later (while still
resolving the prototype parameter to Nothing) and we in that case we
prioritize according to the target method, after which we fallback to
the default procedure.
jchyb added a commit to jchyb/dotty that referenced this issue Jan 9, 2023
This was a problem because it could it get in the way of some
metaprogramming techniques. The main issue was the fact that when typing
functions, the type inference would first look at the types from the
source method (resolving type wildcards to Nothing) and only after that,
it could look at the target method.
Now, in the case of wildcards we save that fact for later (while still
resolving the prototype parameter to Nothing) and we in that case we
prioritize according to the target method, after which we fallback to
the default procedure.
jchyb added a commit to jchyb/dotty that referenced this issue Jan 9, 2023
This was a problem because it could it get in the way of some
metaprogramming techniques. The main issue was the fact that when typing
functions, the type inference would first look at the types from the
source method (resolving type wildcards to Nothing) and only after that,
it could look at the target method.
Now, in the case of wildcards we save that fact for later (while still
resolving the prototype parameter to Nothing) and we in that case we
prioritize according to the target method, after which we fallback to
the default procedure.
jchyb added a commit to jchyb/dotty that referenced this issue Jan 9, 2023
This was a problem because it could it get in the way of some
metaprogramming techniques. The main issue was the fact that when typing
functions, the type inference would first look at the types from the
source method (resolving type wildcards to Nothing) and only after that,
it could look at the target method.
Now, in the case of wildcards we save that fact for later (while still
resolving the prototype parameter to Nothing) and we in that case we
prioritize according to the target method, after which we fallback to
the default procedure.
jchyb added a commit to jchyb/dotty that referenced this issue Jan 11, 2023
This was a problem because it could it get in the way of some
metaprogramming techniques. The main issue was the fact that when typing
functions, the type inference would first look at the types from the
source method (resolving type wildcards to Nothing) and only after that,
it could look at the target method.
Now, in the case of wildcards we save that fact for later (while still
resolving the prototype parameter to Nothing) and we in that case we
prioritize according to the target method, after which we fallback to
the default procedure.
odersky added a commit that referenced this issue Jan 26, 2023
Fixes #16405, which was a
problem because it could it get in the way of some metaprogramming
techniques. The main issue was the fact that when typing functions, the
type inference would first look at the types from the source method (in
decomposeProtoFunction resolving found type wildcards to Nothing) and
only after that, it could look at the target method.

This is a continuation and simplification of #16625
@Kordyjan Kordyjan modified the milestones: Future versions, 3.3.1 Aug 1, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment