Skip to content

Commit 17a6ab0

Browse files
authored
Merge pull request #12560 from dotty-staging/improve-typeinf
Harden Type Inference
2 parents 1f4d125 + 8a2158c commit 17a6ab0

File tree

10 files changed

+35
-19
lines changed

10 files changed

+35
-19
lines changed

compiler/src/dotty/tools/dotc/typer/Inferencing.scala

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,10 @@ object Inferencing {
3333
*/
3434
def isFullyDefined(tp: Type, force: ForceDegree.Value)(using Context): Boolean = {
3535
val nestedCtx = ctx.fresh.setNewTyperState()
36-
val result = new IsFullyDefinedAccumulator(force)(using nestedCtx).process(tp)
36+
val result =
37+
try new IsFullyDefinedAccumulator(force)(using nestedCtx).process(tp)
38+
catch case ex: StackOverflowError =>
39+
false // can happen for programs with illegal recusions, e.g. neg/recursive-lower-constraint.scala
3740
if (result) nestedCtx.typerState.commit()
3841
result
3942
}
@@ -43,7 +46,7 @@ object Inferencing {
4346
*/
4447
def canDefineFurther(tp: Type)(using Context): Boolean =
4548
val prevConstraint = ctx.typerState.constraint
46-
isFullyDefined(tp, force = ForceDegree.all)
49+
isFullyDefined(tp, force = ForceDegree.failBottom)
4750
&& (ctx.typerState.constraint ne prevConstraint)
4851

4952
/** The fully defined type, where all type variables are forced.
@@ -687,7 +690,7 @@ trait Inferencing { this: Typer =>
687690

688691
val arg = findArg(call)
689692
if !arg.isEmpty then
690-
var argType = arg.tpe
693+
var argType = arg.tpe.widenExpr.widenTermRefExpr
691694
if !argType.isSingleton then argType = SkolemType(argType)
692695
argType <:< tvar
693696
case _ =>

compiler/src/dotty/tools/dotc/typer/ReTyper.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,4 +134,5 @@ class ReTyper extends Typer with ReChecking {
134134
override protected def addAccessorDefs(cls: Symbol, body: List[Tree])(using Context): List[Tree] = body
135135
override protected def checkEqualityEvidence(tree: tpd.Tree, pt: Type)(using Context): Unit = ()
136136
override protected def matchingApply(methType: MethodOrPoly, pt: FunProto)(using Context): Boolean = true
137+
override protected def typedScala2MacroBody(call: untpd.Tree)(using Context): Tree = promote(call)
137138
}

compiler/src/dotty/tools/dotc/typer/Typer.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3685,7 +3685,7 @@ class Typer extends Namer
36853685
return readapt(tree.cast(target))
36863686

36873687
def recover(failure: SearchFailureType) =
3688-
if canDefineFurther(wtp) then readapt(tree)
3688+
if canDefineFurther(wtp) || canDefineFurther(pt) then readapt(tree)
36893689
else err.typeMismatch(tree, pt, failure)
36903690

36913691
pt match
@@ -3907,7 +3907,7 @@ class Typer extends Namer
39073907
report.warning(PureExpressionInStatementPosition(original, exprOwner), original.srcPos)
39083908

39093909
/** Types the body Scala 2 macro declaration `def f = macro <body>` */
3910-
private def typedScala2MacroBody(call: untpd.Tree)(using Context): Tree =
3910+
protected def typedScala2MacroBody(call: untpd.Tree)(using Context): Tree =
39113911
// TODO check that call is to a method with valid signature
39123912
def typedPrefix(tree: untpd.RefTree)(splice: Context ?=> Tree => Tree)(using Context): Tree = {
39133913
tryAlternatively {

tests/neg-scalajs/jsconstructortag-error-in-typer.check

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
|no implicit argument of type scala.scalajs.js.ConstructorTag[ScalaClass] was found for parameter tag of method constructorTag in package scala.scalajs.js.
55
|I found:
66
|
7-
| scala.scalajs.js.ConstructorTag.materialize[Nothing]
7+
| scala.scalajs.js.ConstructorTag.materialize[T]
88
|
99
|But method materialize in object ConstructorTag does not match type scala.scalajs.js.ConstructorTag[ScalaClass].
1010
-- Error: tests/neg-scalajs/jsconstructortag-error-in-typer.scala:10:39 ------------------------------------------------
@@ -13,7 +13,7 @@
1313
|no implicit argument of type scala.scalajs.js.ConstructorTag[ScalaTrait] was found for parameter tag of method constructorTag in package scala.scalajs.js.
1414
|I found:
1515
|
16-
| scala.scalajs.js.ConstructorTag.materialize[Nothing]
16+
| scala.scalajs.js.ConstructorTag.materialize[T]
1717
|
1818
|But method materialize in object ConstructorTag does not match type scala.scalajs.js.ConstructorTag[ScalaTrait].
1919
-- Error: tests/neg-scalajs/jsconstructortag-error-in-typer.scala:11:45 ------------------------------------------------
@@ -22,6 +22,6 @@
2222
|no implicit argument of type scala.scalajs.js.ConstructorTag[ScalaObject.type] was found for parameter tag of method constructorTag in package scala.scalajs.js.
2323
|I found:
2424
|
25-
| scala.scalajs.js.ConstructorTag.materialize[Nothing]
25+
| scala.scalajs.js.ConstructorTag.materialize[T]
2626
|
2727
|But method materialize in object ConstructorTag does not match type scala.scalajs.js.ConstructorTag[ScalaObject.type].

tests/neg/i4986a.check

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@
44
|Cannot construct a collection of type List[String] with elements of type Int based on a collection of type List[Int]..
55
|I found:
66
|
7-
| collection.BuildFrom.buildFromIterableOps[Nothing, Nothing, Nothing]
7+
| collection.BuildFrom.buildFromIterableOps[CC, A0, A]
88
|
99
|But method buildFromIterableOps in trait BuildFromLowPriority2 does not match type collection.BuildFrom[List[Int], Int, List[String]].

tests/neg/i7056.check

Lines changed: 0 additions & 7 deletions
This file was deleted.

tests/pos/i864.scala renamed to tests/neg/i864.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,5 @@ object C {
66
trait X[T]
77
implicit def u[A, B]: X[A | B] = new X[A | B] {}
88
def y[T](implicit x: X[T]): T = ???
9-
val x: a.type & b.type | b.type & c.type = y
9+
val x: a.type & b.type | b.type & c.type = y // error
1010
}

tests/pos/typeclass-encoding2.scala renamed to tests/neg/typeclass-encoding3.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -344,5 +344,6 @@ object functors {
344344
??? // $this.flatMap[A](identity) disabled since it does not typecheck
345345
}
346346

347-
MonadFlatten.flattened(List(List(1, 2, 3), List(4, 5)))
347+
MonadFlatten.flattened(List(List(1, 2, 3), List(4, 5))) // ok, synthesizes (using ListMonad)
348+
MonadFlatten.flattened(List(List(1, 2, 3), List(4, 5)))(using ListMonad) // error
348349
}

tests/pos/depfun.scala

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// The following test is derived from scala/reflect/TypeTest.scala, but using
2+
// a dependent function instead of a dependent SAM. It shows that the special treatment
3+
// using a DependentTypeTree is not needed for plain function types.
4+
// But for SAM types, the treatment is needed, otherwise TypeTest.scala does
5+
// not typecheck. Todo: Figure out the reason for this difference.
6+
object Test:
7+
8+
type F[S, T] = (x: S) => Option[x.type & T]
9+
10+
/** Trivial type test that always succeeds */
11+
def identity[T]: F[T, T] = Some(_)
12+
13+
val x: 1 = 1
14+
val y = identity(x)
15+
val z: Option[1] = y
16+
17+

tests/neg/i7056.scala renamed to tests/pos/i7056.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,5 @@ given [T <: A](using PartialId[T]): T1[T] = new T1[T] {
1616
given PartialId[B] = ???
1717

1818
val x: B = ???
19-
val z = x.idnt1 // error
19+
val z = x.idnt1 // used to be an error, now ok
20+

0 commit comments

Comments
 (0)