-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Allow refinements that refine already refined types. #244
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
Conversation
Previously, a double definition errorfor `T` was produced in a case like this: type T1 = C { T <: A } type T2 = T1 { T <: B } This was caused by the way T1 was treated in the refinement class that is used to typecheck the type. Desugaring of T2 with `refinedTypeToClass` would give trait <refinement> extends T1 { type T <: B } and `normalizeToClassRefs` would transform this to: trait <refinement> extends C { type T <: A; type T <: B } Hence the double definition. The new scheme desugars the rhs of `T2` to: trait <refinement> extends C { this: T1 => type T <: B } which avoids the problem. Also, added tests that scala#232 (fix/boundsPropagation) indeed considers all refinements together when comparing refined types.
case tp: RefinedType if tp.argInfos.nonEmpty => tp // parameterized class type | ||
case tp: TypeRef if tp.symbol.isClass => tp // monomorphic class type | ||
case tp: TypeProxy => stripToCore(tp.underlying) | ||
case _ => defn.AnyType |
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.
Was this changed intentionally from Object
to Any
? If so, why?
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.
Yes that was intentional. It seems that Any is the more natural parent type for a purely structural type.
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.
Agreed. I remember this coming up as a rough edge between value classes and structural types:
scala> trait T extends Any { def t }
defined trait T
scala> def foo(c: { def t} ) = c.t
warning: there was one feature warning; re-run with -feature for details
foo: (c: AnyRef{def t: Unit})Unit
scala> def test(t: T) = foo(t)
<console>:9: error: type mismatch;
found : t.type (with underlying type T)
required: AnyRef{def t: Unit}
def test(t: T) = foo(t)
^
It would be interesting to experiment with changing this in scalac and running the community build to find out how compatible it is.
LGTM. |
Yes, I think the reason for AnyRef parent for structural types is historical. Structural types came before value classes and were represented as traits. Since traits could not have an Any parent then, it was logical to pick AnyRef. |
Allow refinements that refine already refined types.
Backport "Fix copy of annotation on @main methods" to 3.3 LTS
Previously, a double definition errorfor
T
was produced in a case like this:This was caused by the way T1 was treated in the refinement class
that is used to typecheck the type. Desugaring of T2 with
refinedTypeToClass
would give
and
normalizeToClassRefs
would transform this to:Hence the double definition. The new scheme desugars the rhs of
T2
to:which avoids the problem.
Also, added tests that #232 (fix/boundsPropagation) indeed considers all refinements
together when comparing refined types.
Supersedes #243. Review by @retronym please.