Skip to content

Typing deviation in getOrElse #1045

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

Closed
DarkDimius opened this issue Jan 26, 2016 · 3 comments
Closed

Typing deviation in getOrElse #1045

DarkDimius opened this issue Jan 26, 2016 · 3 comments

Comments

@DarkDimius
Copy link
Contributor

import scala.collection._
object T {
  val newSymbolMap: mutable.HashMap[String, mutable.HashMap[Int, Double]] = mutable.HashMap.empty
  val map = newSymbolMap.getOrElse("a", mutable.HashMap.empty)
  map.put(1, 0.0)
  newSymbolMap.put("a", map)
}

Compiles fine with scalac. Fails in dotty:

reproduce.scala:5: error: type mismatch:
 found   : Int(1)
 required: T.map.A
  map.put(1, 0.0)
          ^
reproduce.scala:5: error: type mismatch:
 found   : Double(0.0)
 required: T.map.B
  map.put(1, 0.0)
             ^
reproduce.scala:6: error: type mismatch:
 found   : (scala.collection.mutable.HashMap[Int, Double] |
  scala.collection.mutable.HashMap[Nothing, Nothing]
)(T.map)
 required: collection.mutable.HashMap[Int, Double]
  newSymbolMap.put("a", map)
                        ^
three warnings found
three errors found

This code is part of #630 and it used to compile fine.

@DarkDimius
Copy link
Contributor Author

Specifying the type of map: mutable.HashMap[Int, Double] is a workaround.

@smarter
Copy link
Member

smarter commented Jan 26, 2016

Quick analysis which might be wrong, I haven't checked it:
When we do type inference for newSymbolMap.getOrElse we start with:

B1 >: scala.collection.mutable.HashMap[Int, Double]

where B1 corresponds to the type parameter of getOrElse, then since we apply it to ("a", mutable.HashMap.empty), we get:

B1 >: scala.collection.mutable.HashMap[Int, Double] | scala.collection.mutable.HashMap[A, B]
A unconstrained
B unconstrained

where A and B correspond to the type parameters of HashMap.empty.

Afterwards, we instantiate the tvars:

  1. B1 is instantiated to scala.collection.mutable.HashMap[Int, Double] | scala.collection.mutable.HashMap[A, B] (the union is not approximated because it contains uninstantiated tvars, this is false, see next comment)
  2. A and B are instantiated to Nothing because they are unconstrained

I'm not sure how to fix this right now.

@smarter
Copy link
Member

smarter commented Jan 26, 2016

Actually, the issue seems to be in approximateUnion which we do call on scala.collection.mutable.HashMap[Int, Double] | scala.collection.mutable.HashMap[A, B], it should return a non-union type (and thus constrain A and B properly and fix the issue we're seeing) but it calls baseTypeWithArgs which calls | (https://github.com/lampepfl/dotty/blob/93dd1cf1fdbf56ca3c153aa5a25fb4c48782acf5/src/dotty/tools/dotc/core/TypeApplications.scala#L610-L611) and we end up back with a union type. This is the case since ee76fda which changed the behavior of |.

This should be easy to fix: instead of calling | in baseTypeWithArgs we should call a method that does distribute unions inside refinement types because this is what we want in this particular case.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants