-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Spurious 'type is not a member' #15177
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
Comments
@OlegYch not sure if I got this right. Do you mean there are some cases when changing the order of declaration of a class and its companion doesn't make the code compile? Could you give an example then? |
@prolativ yep that's what i mean |
sometimes it would compile incrementally, but fail after clean |
If you have any unminimized examples, that would be helpful too anyway |
for example this compiles incrementally, but doesn't after clean |
I haven't managed to reproduce the problem for this case ...
in another file and then try to compile both files with a single |
@prolativ yep |
any news on this? |
a bit simpler repro: class X[T] {
type Id = T
}
object A extends X[B]
class B(id: A.Id) |
still an issue on |
a workaround is to delete type parameter... class X {
type Id
}
object A extends X {
type Id = B
}
class B(id: A.Id) |
still an issue on 3.2.2 |
Dale points out that as in, this compiles! (just swapping the order of class X[T] {
type Id = T
}
class B(id: A.Id)
object A extends X[B] |
yes, it is pretty random |
I ran into the same problem in #16924, because there's a test case in the repo that has a somewhat similar situation, where if one file is typed before the other, with my change you end up querying the children of a top level sealed trait before typing and discovering a nested second child... This issue seems like the easier version of the problem to study. |
an alternate form that also fails: class X[T] { trait Id }
object A extends X[B]
class B(id: A.Id) this seems slightly simpler to me — it shows that we need a type parameter ( it's unfortunate that the compiler feels it needs to process B's constructor so early. at the time A first mentions B, we need to enter B, but can we put off looking at B's constructor until later? |
Dale has found that the |
a user on Discord hit this today — their version looks like https://scastie.scala-lang.org/KmklIKFYTmKzmeEgwNQfuA |
or more kindly |
So, we can short-circuit the kindness check for the Oleg's minimisation: + val selfParams = self.typeParams
+ val otherParams = other.typeParams
+ if selfParams.isEmpty && otherParams.isEmpty then true // defer calling hkResult to avoid completing types
+ else
val selfResult = self.hkResult
val otherResult = other.hkResult But then what about the same case, with only the change that the referenced type actually is higher-kinded? // like tests/pos/i15177.scala but with B being higher kinded
class X[T[_]] {
type Id
}
object A extends X[B]
class B[C](id: A.Id) Well, before we even get to doing the kind checks for So, then, why does completing /** Ensure constructor is completed so that any parameter accessors
* which have type trees deriving from its parameters can be
* completed in turn. Note that parent types access such parameter
* accessors, that's why the constructor needs to be completed before
* the parent types are elaborated.
*/
def completeConstructor(denot: SymDenotation): Unit = { So should we fix it for non-higher kinded types only? I think that would fix the FakeEnum case too. |
@smarter wdyt? Should we try and allow some of this? I have a patch that makes some attempts at progress for the applied type case ( |
I've been thinking on whether even a partial solution could be considered sufficient. Naturally we can't in general promise to support absolutely everything that compiled in Scala 2. But we should default to trying to, within reason, depending on context. And here the context is a code pattern that looks simple enough and reasonable enough to me, plus it's been hit by multiple users, that I think we should try for backward compatibility for the known use cases, even if we don't have a fully general solution. |
They can be part of the parent tree ( |
Dale has an idea where instead of eagerly traversing B’s entire constructor, we would only traverse its type parameters (if it has any, e.g. in the (This wouldn't help the |
This is the approach taken in his PR (#17086). |
Compiler version
3.0.0 - 3.2.0-RC1-bin-20220511-7c446ce-NIGHTLY
Minimized code
Output
Explanation
This always compiles fine on 2.13 and sometimes on 3. I couldn't find the exact rule when it compiles and when it doesn't.
In the example above it would compile fine if i move case class definition before object, but in other cases this doesn't help.
The text was updated successfully, but these errors were encountered: