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

Show GADT bounds in type mismatch message #3990

Merged
merged 2 commits into from
Feb 21, 2018

Conversation

smarter
Copy link
Member

@smarter smarter commented Feb 12, 2018

The inferred GADT bounds can be non-trivial so it makes sense to display
them.

This commit also showcases the now-improved GADT support in Dotty (both
tests/pos/gadt-eval.scala and tests/neg/gadt-eval.scala used to compile,
and both compile in Scala 2).

@smarter smarter requested a review from odersky February 12, 2018 18:12
// | found: (_$1, _$1)
// | required: T
// |
// | where: T is a type in method eval which is an alias of (_$1, _$2)
Copy link
Contributor

Choose a reason for hiding this comment

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

This overall testcase is cool!

Wondering how to explain where these type variables come from. They come from the match (hard to show), and they show up in the types of a and b, which is easier to show, most easily by showing the whole typing context. That might be too much, but I think GHC sometimes does it, and both Agda and Coq absolutely do it and have to do it. Not sure where to draw a line.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, if you can think of a good way to display this information I'm interested, I haven't checked what other compilers do.

Copy link
Contributor

Choose a reason for hiding this comment

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

I don't get it. If "T is a type in method eval which is an alias of (_$1, _$2)", why is there a type error?

Copy link
Contributor

Choose a reason for hiding this comment

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

found: (_$1, _$1) 
expected: (_$1, _$2) 

The second type parameter of the tuple differs

case sym: Symbol =>
ctx.gadt.bounds.contains(sym) && ctx.gadt.bounds(sym) != TypeBounds.empty
case _ =>
false
Copy link
Contributor

Choose a reason for hiding this comment

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

assert(false, "unreachable")?

The inferred GADT bounds can be non-trivial so it makes sense to display
them.

This commit also showcases the now-improved GADT support in Dotty (both
tests/pos/gadt-eval.scala and tests/neg/gadt-eval.scala used to compile,
and both compile in Scala 2).
We no longer convert GADT bounds into normal bounds since scala#3233 was
merged.
if (ctx.gadt.bounds.contains(sym))
sym.info & ctx.gadt.bounds(sym)
else
sym.info
Copy link
Contributor

Choose a reason for hiding this comment

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

micro optimisation:

val bounds = ctx.gadt.bounds(sym)
val info = if (bounds != null) sym.info & bounds else sym.info

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 don't think micro-optimizing error messages is worth it.

@@ -183,7 +188,11 @@ object Formatting {
def needsExplanation(entry: Recorded) = entry match {
case param: TypeParamRef => ctx.typerState.constraint.contains(param)
case skolem: SkolemType => true
case _ => false
case sym: Symbol =>
ctx.gadt.bounds.contains(sym) && ctx.gadt.bounds(sym) != TypeBounds.empty
Copy link
Contributor

Choose a reason for hiding this comment

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

micro optimisation:

ctx.gadt.bounds(sym) != TypeBounds.empty // since it returns null if not in the gadt bounds map

Copy link
Member Author

Choose a reason for hiding this comment

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

we would also have to check != null

s"is a ${ctx.printer.kindString(sym)}${sym.showExtendedLocation}${addendum("bounds", sym.info)}"
val info =
if (ctx.gadt.bounds.contains(sym))
sym.info & ctx.gadt.bounds(sym)
Copy link
Contributor

Choose a reason for hiding this comment

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

Do you need to do the intersection? Can you simply return ctx.gadt.bounds(sym)?

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 think so, we used to do something similar in PostTyper.

Copy link
Contributor

@odersky odersky left a comment

Choose a reason for hiding this comment

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

LGTM

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