-
Notifications
You must be signed in to change notification settings - Fork 531
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
Avoid creating Typeable for general type projections #803
Conversation
Could you add a test that |
You mean for an unrelated type? |
71b9610
to
9157dca
Compare
I'm looking at the comment above the code you replaced,
I'd like to see a test which verifies that unsound cases are still rejected. |
Something like this maybe? trait Outer {
type T
class Inner(val t: T)
def boom(a: Any): Option[Inner] = a.cast[Inner]
}
val i = new Outer { type T = Int }
val ii = new i.Inner(23)
val s = new Outer { type T = String }
s.boom(ii) // If Outer compiles then this should be None |
There are existing tests for type projections in Or maybe something like |
I found an unsound example: @Test
def testTypeProjection(): Unit = {
trait Outer {
type T
class Inner(val t: T)
}
trait OuterInt extends Outer {
type T = Int
}
trait OuterStr extends Outer {
type T = String
}
val typ = Typeable[OuterInt#Inner]
val outStr = new OuterStr { }
assertEquals(None, typ.cast(new outStr.Inner("boom")))
} However, note that the check in One option would be to just reject all type projections. |
When you say "type projection" do you mean "abstract type member"? |
Ahh, you mean type projections as the target of the cast? |
Yes, I mean instances of |
Apropo, regular pattern matching has the same problem. It will warn for erasure on |
I just checked my earlier example, @Test
def testRefined: Unit = {
trait Outer {
type T
class Inner(val t: T)
def boom(a: Any): Option[Inner] = a.cast[Inner]
}
val i = new Outer { type T = Int }
val ii = new i.Inner(23)
val s = new Outer { type T = String }
//assert(!s.boom(ii).isDefined) // If Outer compiles then this should be None}
s.boom(ii).map(_.t.length) // CCE
} This blows up with a
Conclusion: there should be no |
Interestingly, in your example, I think there should be an instance for |
@milessabin in your example we don't have a type projection, but a path dependent type. As such, the outer reference should be compared for equality (see #798). Yes, I guess my example should have a But what if there is a third class nested inside |
9157dca
to
fbb23b6
Compare
Codecov Report
@@ Coverage Diff @@
## master #803 +/- ##
=========================================
Coverage ? 87.99%
=========================================
Files ? 64
Lines ? 1499
Branches ? 4
=========================================
Hits ? 1319
Misses ? 180
Partials ? 0
Continue to review full report at Codecov.
|
a1a30f3
to
da4c4ea
Compare
da4c4ea
to
df92d35
Compare
df92d35
to
4eaa1ee
Compare
Unless: * the outer type is final and not parametrized * the inner type is a case class All other type projections are potentially unsound because the inner type can capture type members of the outer type.
4eaa1ee
to
2ebc466
Compare
I'm going to defer to your judgement on this one. |
If you approve I will merge it 😄 - it's the last of a series of fixes in |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!
Unless:
All other type projections are potentially unsound because the
inner type can capture type members of the outer type.
Closes #579
Closes #848