Skip to content

SI-6541 valid wildcard existentials for case-module-unapply#4017

Merged
lrytz merged 2 commits intoscala:2.11.xfrom
lrytz:t6541
Nov 5, 2014
Merged

SI-6541 valid wildcard existentials for case-module-unapply#4017
lrytz merged 2 commits intoscala:2.11.xfrom
lrytz:t6541

Conversation

@lrytz
Copy link
Member

@lrytz lrytz commented Sep 30, 2014

Instead of letting the compiler infer the return type of case module
unapply methods, provide them explicitly.

@lrytz
Copy link
Member Author

lrytz commented Sep 30, 2014

Review by @retronym

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This ain't hygenic.

case class C2(b: Tuple1[_ <: String])
object C2 {
  class String
}
test/files/run/t6541.scala:28: error: type mismatch;
 found   : (_$1(in method apply),) where type _$1(in method apply) <: C2.String
 required: Tuple1[_ <: String]
case class C2(b: Tuple1[_ <: String])
           ^

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Last time I tried to fix this, I ended up with a custom type completer for unapply to add enough laziness to the mix so we could peek at the info of the case class to derive the type of the unapply method.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right about hygiene. But note that the error message talks about apply (not unapply), so this failure is not introduced by my change. Arguably, the failure is according to the spec: http://www.scala-lang.org/files/archive/spec/2.11/05-classes-and-objects.html#case-classes.

We should do the same for the parameter types of apply and the return type of unapply: both hygienic, or both not.

We should also include copy in the discussion – it's not systematic that it works differently. The problem with copy is that we have a stronger argument for making it hygienic: otherwise we can get a failure even without an explicit shadowing type declaration:

class A {
  class C
  case class B(x: C) extends A { def copy(x: C = this.x) = ... }
}

The class parameter type is A.this.C. If copy was non-hygienic, the parameter type of copy would be B.this.C (since B extends A), so it would not compile.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right you are. In fact, the type parameters of copy are also prone to shadowing.

case class C2[T <: String]() {
  class String
}
% scalac-hash v2.11.2 test/files/run/t6541.scala
test/files/run/t6541.scala:28: error: type arguments [T] do not conform to class C2's type parameter bounds [T <: String]
case class C2[T <: String]() {
           ^
one error found

In this case, we can defer that mess to a new ticket and proceed with this one. Perhaps though it needs to be under -Xsource:2.12 as it changes signatures (albeit in a binary compatible way).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I logged https://issues.scala-lang.org/browse/SI-8884

Good point about compatibility, I only thought about binary.

I'm not sure if -Xsource:2.12 is the right solution here, maybe better submit the PR against 2.12? Because the generated pickle is different, so in some sense it's binary incompatible. If you turn it on to compile a library, then a client might fail to compile against the new binary.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't see a way that enabling this under -Xsource:2.12 would lead to breakage under separate compilation with different flags. The type of the unapply is computed once and stored in the pickle.

@lrytz lrytz assigned retronym and unassigned lrytz Oct 1, 2014
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • constrParamss returns duplicated trees

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But needn't call it twice (once to determine the method name, and again here).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep, thanks!

@retronym
Copy link
Member

retronym commented Oct 1, 2014

Not sure what style we should settle on, but we might consider referring to Option and friends symfully rather that with the root qualified path.

e.g. https://github.com/retronym/scala/compare/review/4017/symful?expand=1

We don't need to change this PR, but let's give it some thought and seek some consistency in how we refer to things from the parser. /cc @densh

@densh
Copy link
Contributor

densh commented Oct 6, 2014

As far as I know the reason we have both root qualified and symbol qualified identifiers emitted by the parser due to the fact that symbol-only approach used to cause cyclic references while bootstrapping standard library. Maybe this is not an issue any more but it needs some investigation.

@lrytz lrytz modified the milestones: 2.11.4, 2.11.3 Oct 6, 2014
@lrytz lrytz modified the milestones: 2.11.4, 2.11.5 Oct 14, 2014
@lrytz lrytz force-pushed the t6541 branch 3 times, most recently from 004060d to a51c9f3 Compare November 3, 2014 16:29
@lrytz lrytz force-pushed the t6541 branch 3 times, most recently from aebc456 to 9a76336 Compare November 4, 2014 08:50
The default value was NoScalaVersion before, because tryToSet (where
the default was supposed to be set) is not called at all if the option
is not specified.

The initial value of Xmigration is set to NoScalaVersion (which it was
before, the AnyScalaVersion argument was ignored). AnyScalaVersion
would be wrong, it would give a warning in `Map(1 -> "eis").values`
if the option was not specified. See tests.
@lrytz
Copy link
Member Author

lrytz commented Nov 4, 2014

The change is now under -Xsource:2.12, re-review by @retronym

@retronym
Copy link
Member

retronym commented Nov 5, 2014

Great! One last thing: can you please add a pos test without the -Xsource:2.12 flag to back up the fact that: val o: Option[Class[T]] forSome { type T } = C.unapply(C(classOf[String])) used to work.

Instead of letting the compiler infer the return type of case module
unapply methods, provide them explicitly.

This is enabled only under -Xsource:2.12, because the change is not
source compatible.
@lrytz
Copy link
Member Author

lrytz commented Nov 5, 2014

@retronym turned it into a repl test

@retronym
Copy link
Member

retronym commented Nov 5, 2014

LGTM

lrytz added a commit that referenced this pull request Nov 5, 2014
SI-6541 valid wildcard existentials for case-module-unapply
@lrytz lrytz merged commit 4949143 into scala:2.11.x Nov 5, 2014
@lrytz lrytz deleted the t6541 branch November 7, 2014 09:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants