Skip to content

Commit 4412a92

Browse files
committed
Value class Depth.
It's the obvious translation from a raw Int into a value class. It wasn't that long ago one could find a signature like this: def merge(tps: List[Type], variance: Int, depth: Int): Type Do you feel lucky, method caller? Well, do ya? Anyway, now it is: def merge(tps: List[Type], variance: Variance, depth: Depth): Type Forget for a moment the fact that you'd probably rather not pass variance for depth and depth for variance and look at the type signatures: (List[Type], Variance, Depth) => Type (List[Type], Int, Int) => Type
1 parent 9e81f00 commit 4412a92

File tree

11 files changed

+166
-161
lines changed

11 files changed

+166
-161
lines changed

src/compiler/scala/reflect/macros/compiler/Validators.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ trait Validators {
5757
checkMacroImplResultTypeMismatch(atpeToRtpe(aret), rret)
5858

5959
val maxLubDepth = lubDepth(aparamss.flatten map (_.tpe)) max lubDepth(rparamss.flatten map (_.tpe))
60-
val atargs = solvedTypes(atvars, atparams, atparams map varianceInType(aret), upper = false, depth = maxLubDepth)
60+
val atargs = solvedTypes(atvars, atparams, atparams map varianceInType(aret), upper = false, maxLubDepth)
6161
val boundsOk = typer.silent(_.infer.checkBounds(macroDdef, NoPrefix, NoSymbol, atparams, atargs, ""))
6262
boundsOk match {
6363
case SilentResultValue(true) => // do nothing, success

src/compiler/scala/tools/nsc/typechecker/Implicits.scala

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -644,8 +644,7 @@ trait Implicits {
644644
if (tvars.nonEmpty)
645645
typingLog("solve", ptLine("tvars" -> tvars, "tvars.constr" -> tvars.map(_.constr)))
646646

647-
val targs = solvedTypes(tvars, undetParams, undetParams map varianceInType(pt),
648-
upper = false, lubDepth(List(itree2.tpe, pt)))
647+
val targs = solvedTypes(tvars, undetParams, undetParams map varianceInType(pt), upper = false, lubDepth(itree2.tpe :: pt :: Nil))
649648

650649
// #2421: check that we correctly instantiated type parameters outside of the implicit tree:
651650
checkBounds(itree2, NoPrefix, NoSymbol, undetParams, targs, "inferred ")

src/compiler/scala/tools/nsc/typechecker/Infer.scala

Lines changed: 18 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ package typechecker
99
import scala.collection.{ mutable, immutable }
1010
import scala.util.control.ControlThrowable
1111
import symtab.Flags._
12+
import scala.reflect.internal.Depth
1213

1314
/** This trait contains methods related to type parameter inference.
1415
*
@@ -21,6 +22,7 @@ trait Infer extends Checkable {
2122
import global._
2223
import definitions._
2324
import typeDebug.ptBlock
25+
import typeDebug.str.parentheses
2426
import typingStack.{ printTyping }
2527

2628
/** The formal parameter types corresponding to `formals`.
@@ -132,34 +134,17 @@ trait Infer extends Checkable {
132134
* @param upper When `true` search for max solution else min.
133135
* @throws NoInstance
134136
*/
135-
def solvedTypes(tvars: List[TypeVar], tparams: List[Symbol],
136-
variances: List[Variance], upper: Boolean, depth: Int): List[Type] = {
137-
138-
if (tvars.nonEmpty) {
139-
def tp_s = (tparams, tvars).zipped map { case (tp, tv) => s"${tp.name}/$tv" } mkString ","
140-
printTyping(s"solving for $tp_s")
141-
}
142-
143-
if (!solve(tvars, tparams, variances, upper, depth)) {
144-
// no panic, it's good enough to just guess a solution, we'll find out
145-
// later whether it works. *ZAP* @M danger, Will Robinson! this means
146-
// that you should never trust inferred type arguments!
147-
//
148-
// Need to call checkBounds on the args/typars or type1 on the tree
149-
// for the expression that results from type inference see e.g., #2421:
150-
// implicit search had been ignoring this caveat
151-
// throw new DeferredNoInstance(() =>
152-
// "no solution exists for constraints"+(tvars map boundsString))
137+
def solvedTypes(tvars: List[TypeVar], tparams: List[Symbol], variances: List[Variance], upper: Boolean, depth: Depth): List[Type] = {
138+
if (tvars.isEmpty) Nil else {
139+
printTyping("solving for " + parentheses((tparams, tvars).zipped map ((p, tv) => s"${p.name}: $tv")))
140+
// !!! What should be done with the return value of "solve", which is at present ignored?
141+
// The historical commentary says "no panic, it's good enough to just guess a solution,
142+
// we'll find out later whether it works", meaning don't issue an error here when types
143+
// don't conform to bounds. That means you can never trust the results of implicit search.
144+
// For an example where this was not being heeded, SI-2421.
145+
solve(tvars, tparams, variances, upper, depth)
146+
tvars map instantiate
153147
}
154-
for (tvar <- tvars ; if tvar.constr.inst == tvar) {
155-
if (tvar.origin.typeSymbol.info eq ErrorType)
156-
// this can happen if during solving a cyclic type parameter
157-
// such as T <: T gets completed. See #360
158-
tvar.constr.inst = ErrorType
159-
else
160-
abort(tvar.origin+" at "+tvar.origin.typeSymbol.owner)
161-
}
162-
tvars map instantiate
163148
}
164149

165150
def skipImplicit(tp: Type) = tp match {
@@ -554,10 +539,7 @@ trait Infer extends Checkable {
554539
"argument expression's type is not compatible with formal parameter type" + foundReqMsg(tp1, pt1))
555540
}
556541
}
557-
val targs = solvedTypes(
558-
tvars, tparams, tparams map varianceInTypes(formals),
559-
upper = false, lubDepth(formals) max lubDepth(argtpes)
560-
)
542+
val targs = solvedTypes(tvars, tparams, tparams map varianceInTypes(formals), upper = false, lubDepth(formals) max lubDepth(argtpes))
561543
// Can warn about inferring Any/AnyVal as long as they don't appear
562544
// explicitly anywhere amongst the formal, argument, result, or expected type.
563545
def canWarnAboutAny = !(pt :: restpe :: formals ::: argtpes exists (t => (t contains AnyClass) || (t contains AnyValClass)))
@@ -1030,7 +1012,10 @@ trait Infer extends Checkable {
10301012
val variances =
10311013
if (ctorTp.paramTypes.isEmpty) undetparams map varianceInType(ctorTp)
10321014
else undetparams map varianceInTypes(ctorTp.paramTypes)
1033-
val targs = solvedTypes(tvars, undetparams, variances, upper = true, lubDepth(List(resTp, pt)))
1015+
1016+
// Note: this is the only place where solvedTypes (or, indirectly, solve) is called
1017+
// with upper = true.
1018+
val targs = solvedTypes(tvars, undetparams, variances, upper = true, lubDepth(resTp :: pt :: Nil))
10341019
// checkBounds(tree, NoPrefix, NoSymbol, undetparams, targs, "inferred ")
10351020
// no checkBounds here. If we enable it, test bug602 fails.
10361021
// TODO: reinstate checkBounds, return params that fail to meet their bounds to undetparams
@@ -1099,7 +1084,7 @@ trait Infer extends Checkable {
10991084
val tvars1 = tvars map (_.cloneInternal)
11001085
// Note: right now it's not clear that solving is complete, or how it can be made complete!
11011086
// So we should come back to this and investigate.
1102-
solve(tvars1, tvars1 map (_.origin.typeSymbol), tvars1 map (_ => Variance.Covariant), upper = false)
1087+
solve(tvars1, tvars1 map (_.origin.typeSymbol), tvars1 map (_ => Variance.Covariant), upper = false, Depth.AnyDepth)
11031088
}
11041089

11051090
// this is quite nasty: it destructively changes the info of the syms of e.g., method type params

src/reflect/scala/reflect/internal/BaseTypeSeqs.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -130,9 +130,9 @@ trait BaseTypeSeqs {
130130

131131
lazy val maxDepth = maxDepthOfElems
132132

133-
protected def maxDepthOfElems: Int = {
134-
var d = 0
135-
for (i <- 1 until length) d = max(d, typeDepth(elems(i)))
133+
protected def maxDepthOfElems: Depth = {
134+
var d = Depth.Zero
135+
1 until length foreach (i => d = d max typeDepth(elems(i)))
136136
d
137137
}
138138

@@ -234,7 +234,7 @@ trait BaseTypeSeqs {
234234
override def map(g: Type => Type) = lateMap(g)
235235
override def lateMap(g: Type => Type) = orig.lateMap(x => g(f(x)))
236236
override def exists(p: Type => Boolean) = elems exists (x => p(f(x)))
237-
override protected def maxDepthOfElems: Int = elems.map(x => typeDepth(f(x))).max
237+
override protected def maxDepthOfElems: Depth = elems.map(x => typeDepth(f(x))).max
238238
override def toString = elems.mkString("MBTS(", ",", ")")
239239
}
240240

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package scala
2+
package reflect
3+
package internal
4+
5+
import Depth._
6+
7+
final class Depth private (val depth: Int) extends AnyVal with Ordered[Depth] {
8+
def max(that: Depth): Depth = if (this < that) that else this
9+
def decr(n: Int): Depth = if (isAnyDepth) this else Depth(depth - n)
10+
def incr(n: Int): Depth = if (isAnyDepth) this else Depth(depth + n)
11+
def decr: Depth = decr(1)
12+
def incr: Depth = incr(1)
13+
14+
def isNegative = depth < 0
15+
def isZero = depth == 0
16+
def isAnyDepth = this == AnyDepth
17+
18+
def compare(that: Depth): Int = if (depth < that.depth) -1 else if (this == that) 0 else 1
19+
override def toString = s"Depth($depth)"
20+
}
21+
22+
object Depth {
23+
// A don't care value for the depth parameter in lubs/glbs and related operations.
24+
final val AnyDepth = new Depth(Int.MinValue)
25+
final val Zero = new Depth(0)
26+
27+
@inline final def apply(depth: Int): Depth = if (depth < 0) AnyDepth else new Depth(depth)
28+
}

0 commit comments

Comments
 (0)