Skip to content

Commit 57522df

Browse files
committed
Remove tvars introduced while testing normalizedCompatible
1 parent 2fc299b commit 57522df

10 files changed

+74
-15
lines changed

compiler/src/dotty/tools/dotc/core/Decorators.scala

+3-1
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,9 @@ object Decorators {
292292
case _ => String.valueOf(x).nn
293293

294294
/** Returns the simple class name of `x`. */
295-
def className: String = x.getClass.getSimpleName.nn
295+
def className: String =
296+
if x == null then "<null>"
297+
else x.getClass.getSimpleName.nn
296298

297299
extension [T](x: T)
298300
def assertingErrorsReported(using Context): T = {

compiler/src/dotty/tools/dotc/core/TyperState.scala

+3-2
Original file line numberDiff line numberDiff line change
@@ -139,14 +139,15 @@ class TyperState() {
139139
def uncommittedAncestor: TyperState =
140140
if (isCommitted && previous != null) previous.uncheckedNN.uncommittedAncestor else this
141141

142-
/** Commit typer state so that its information is copied into current typer state
142+
/** Commit `this` typer state by copying information into the current typer state,
143+
* where "current" means contextual, so meaning `ctx.typerState`.
143144
* In addition (1) the owning state of undetermined or temporarily instantiated
144145
* type variables changes from this typer state to the current one. (2) Variables
145146
* that were temporarily instantiated in the current typer state are permanently
146147
* instantiated instead.
147148
*
148149
* A note on merging: An interesting test case is isApplicableSafe.scala. It turns out that this
149-
* requires a context merge using the new `&' operator. Sequence of actions:
150+
* requires a context merge using the new `&` operator. Sequence of actions:
150151
* 1) Typecheck argument in typerstate 1.
151152
* 2) Cache argument.
152153
* 3) Evolve same typer state (to typecheck other arguments, say)

compiler/src/dotty/tools/dotc/core/Types.scala

+2-1
Original file line numberDiff line numberDiff line change
@@ -4124,6 +4124,7 @@ object Types extends TypeUtils {
41244124
protected def prefixString: String = companion.prefixString
41254125
}
41264126

4127+
// Actually.. not cached. MethodOrPoly are `UncachedGroundType`s.
41274128
final class CachedMethodType(paramNames: List[TermName])(paramInfosExp: MethodType => List[Type], resultTypeExp: MethodType => Type, val companion: MethodTypeCompanion)
41284129
extends MethodType(paramNames)(paramInfosExp, resultTypeExp)
41294130

@@ -4879,7 +4880,7 @@ object Types extends TypeUtils {
48794880
def origin: TypeParamRef = currentOrigin
48804881

48814882
/** Set origin to new parameter. Called if we merge two conflicting constraints.
4882-
* See OrderingConstraint#merge, OrderingConstraint#rename
4883+
* See OrderingConstraint#merge
48834884
*/
48844885
def setOrigin(p: TypeParamRef) = currentOrigin = p
48854886

compiler/src/dotty/tools/dotc/printing/Formatting.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ object Formatting {
175175
* The idea is to do this for known cases that are useful and then fall back
176176
* on regular syntax highlighting for the cases which are unhandled.
177177
*
178-
* Please not that if used in combination with `disambiguateTypes` the
178+
* Please note that if used in combination with `disambiguateTypes` the
179179
* correct `Context` for printing should also be passed when calling the
180180
* method.
181181
*

compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,7 @@ class PlainPrinter(_ctx: Context) extends Printer {
253253
toTextCapturing(parent, refsText, "") ~ Str("R").provided(printDebug)
254254
else toText(parent)
255255
case tp: PreviousErrorType if ctx.settings.XprintTypes.value =>
256-
"<error>" // do not print previously reported error message because they may try to print this error type again recuresevely
256+
"<error>" // do not print previously reported error message because they may try to print this error type again recursively
257257
case tp: ErrorType =>
258258
s"<error ${tp.msg.message}>"
259259
case tp: WildcardType =>

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

+8
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,14 @@ object ProtoTypes {
7171
|constraint was: ${ctx.typerState.constraint}
7272
|constraint now: ${newctx.typerState.constraint}""")
7373
if result && (ctx.typerState.constraint ne newctx.typerState.constraint) then
74+
// Remove all type lambdas and tvars introduced by testCompat
75+
for tvar <- newctx.typerState.ownedVars do
76+
val tl = tvar.origin.binder
77+
newctx.typerState.ownedVars -= tvar
78+
if newctx.typerState.constraint.contains(tl) then
79+
newctx.typerState.constraint = newctx.typerState.constraint.remove(tl)(using newctx)
80+
81+
// commit any remaining changes in typer state
7482
newctx.typerState.commit()
7583
result
7684
case _ => testCompat

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

+9-8
Original file line numberDiff line numberDiff line change
@@ -360,20 +360,21 @@ trait TypeAssigner {
360360
resultType1)
361361
}
362362
}
363+
else if !args.hasSameLengthAs(paramNames) then
364+
wrongNumberOfTypeArgs(fn.tpe, pt.typeParams, args, tree.srcPos)
363365
else {
364366
// Make sure arguments don't contain the type `pt` itself.
365-
// make a copy of the argument if that's the case.
367+
// Make a copy of `pt` if that's the case.
366368
// This is done to compensate for the fact that normally every
367369
// reference to a polytype would have to be a fresh copy of that type,
368370
// but we want to avoid that because it would increase compilation cost.
369371
// See pos/i6682a.scala for a test case where the defensive copying matters.
370-
val ensureFresh = new TypeMap with CaptureSet.IdempotentCaptRefMap:
371-
def apply(tp: Type) = mapOver(
372-
if tp eq pt then pt.newLikeThis(pt.paramNames, pt.paramInfos, pt.resType)
373-
else tp)
374-
val argTypes = args.tpes.mapConserve(ensureFresh)
375-
if (argTypes.hasSameLengthAs(paramNames)) pt.instantiate(argTypes)
376-
else wrongNumberOfTypeArgs(fn.tpe, pt.typeParams, args, tree.srcPos)
372+
val needsFresh = new ExistsAccumulator(_ eq pt, StopAt.None, forceLazy = true)
373+
val argTypes = args.tpes
374+
val pt1 = if argTypes.exists(needsFresh(false, _)) then
375+
pt.newLikeThis(pt.paramNames, pt.paramInfos, pt.resType)
376+
else pt
377+
pt1.instantiate(argTypes)
377378
}
378379
}
379380
case err: ErrorType =>

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

+23-1
Original file line numberDiff line numberDiff line change
@@ -4736,7 +4736,29 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
47364736
var typeArgs = tree match
47374737
case Select(qual, nme.CONSTRUCTOR) => qual.tpe.widenDealias.argTypesLo.map(TypeTree(_))
47384738
case _ => Nil
4739-
if typeArgs.isEmpty then typeArgs = constrained(poly, tree)._2.map(_.wrapInTypeTree(tree))
4739+
if typeArgs.isEmpty then
4740+
val poly1 = tree match
4741+
case Select(qual, nme.apply) => qual.tpe.widen match
4742+
case defn.PolyFunctionOf(_) =>
4743+
// Given a poly function, like the one in i6682a:
4744+
// val v = [T] => (y:T) => (x:y.type) => 3
4745+
// It's possible to apply `v(v)` which extends to:
4746+
// v.apply[?T](v)
4747+
// Requiring the circular constraint `v <: ?T`,
4748+
// (because type parameter T occurs in v's type).
4749+
// So we create a fresh copy of the outer
4750+
// poly method type, so we now extend to:
4751+
// v.apply[?T'](v)
4752+
// Where `?T'` is a type var for a T' type parameter,
4753+
// leading to the non-circular `v <: ?T'` constraint.
4754+
//
4755+
// This also happens in `assignType(tree: untpd.TypeApply, ..)`
4756+
// to avoid any type arguments, containing the type lambda,
4757+
// being applied to the very same type lambda.
4758+
poly.newLikeThis(poly.paramNames, poly.paramInfos, poly.resType)
4759+
case _ => poly
4760+
case _ => poly
4761+
typeArgs = constrained(poly1, tree)._2.map(_.wrapInTypeTree(tree))
47404762
convertNewGenericArray(readapt(tree.appliedToTypeTrees(typeArgs)))
47414763
case wtp =>
47424764
val isStructuralCall = wtp.isValueType && isStructuralTermSelectOrApply(tree)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// A minimisation of interleaving-overload
2+
// Used while developing the tvar/tl clearnup in normalizedCompatible
3+
class B[U]
4+
class Test():
5+
def fn[T]: [U] => Int => B[U] = [U] => (x: Int) => new B[U]()
6+
def test(): Unit =
7+
fn(1)
8+
fn(2)
9+
()

tests/pos/zipped.min.scala

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Justifies the need for TypeApply in tryInsertImplicitOnQualifier
2+
// after failing ys.map[?B, C] using Zipped2's map
3+
// we want to try ys.map[?B] using Coll's map, after toColl
4+
final class Coll[+A]:
5+
def map[B](f: A => B): Coll[B] = new Coll[B]
6+
def lazyZip[B](that: Coll[B]): Zipped2[A, B] = new Zipped2[A, B](this, that)
7+
final class Zipped2[+X, +Y](xs: Coll[X], ys: Coll[Y]):
8+
def map[B, C](f: (X, Y) => B): Coll[C] = new Coll[C]
9+
object Zipped2:
10+
import scala.language.implicitConversions
11+
implicit def toColl[X, Y](zipped2: Zipped2[X, Y]): Coll[(X, Y)] = new Coll[(X, Y)]
12+
class Test:
13+
def test(xs: Coll[Int]): Unit =
14+
val ys = xs.lazyZip(xs)
15+
ys.map((x: (Int, Int)) => x._1 + x._2)

0 commit comments

Comments
 (0)