Skip to content

Commit f5f9d0f

Browse files
authored
Merge pull request #393 from scala/backport-lts-3.3-22839
Backport "Avoid loosing denotations of named types during `integrate`" to 3.3 LTS
2 parents 2e698b6 + 5133a02 commit f5f9d0f

File tree

5 files changed

+51
-27
lines changed

5 files changed

+51
-27
lines changed

compiler/src/dotty/tools/dotc/ast/tpd.scala

-8
Original file line numberDiff line numberDiff line change
@@ -832,14 +832,6 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
832832
Closure(tree: Tree)(env, meth, tpt)
833833
}
834834

835-
// This is a more fault-tolerant copier that does not cause errors when
836-
// function types in applications are undefined.
837-
// This was called `Inliner.InlineCopier` before 3.6.3.
838-
class ConservativeTreeCopier() extends TypedTreeCopier:
839-
override def Apply(tree: Tree)(fun: Tree, args: List[Tree])(using Context): Apply =
840-
if fun.tpe.widen.exists then super.Apply(tree)(fun, args)
841-
else untpd.cpy.Apply(tree)(fun, args).withTypeUnchecked(tree.tpe)
842-
843835
override def skipTransform(tree: Tree)(using Context): Boolean = tree.tpe.isError
844836

845837
implicit class TreeOps[ThisTree <: tpd.Tree](private val tree: ThisTree) extends AnyVal {

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

+40-9
Original file line numberDiff line numberDiff line change
@@ -3730,9 +3730,47 @@ object Types extends TypeUtils {
37303730
def integrate(tparams: List[ParamInfo], tp: Type)(using Context): Type =
37313731
(tparams: @unchecked) match {
37323732
case LambdaParam(lam, _) :: _ => tp.subst(lam, this) // This is where the precondition is necessary.
3733-
case params: List[Symbol @unchecked] => tp.subst(params, paramRefs)
3733+
case params: List[Symbol @unchecked] => IntegrateMap(params, paramRefs)(tp)
37343734
}
37353735

3736+
/** A map that replaces references to symbols in `params` by the types in
3737+
* `paramRefs`.
3738+
*
3739+
* It is similar to [[Substituters#subst]] but avoids reloading denotations
3740+
* of named types by overriding `derivedSelect`.
3741+
*
3742+
* This is needed because during integration, [[TermParamRef]]s refer to a
3743+
* [[LambdaType]] that is not yet fully constructed, in particular for wich
3744+
* `paramInfos` is `null`. In that case all [[TermParamRef]]s have
3745+
* [[NoType]] as underlying type. Reloading denotions of selections
3746+
* involving such [[TermParamRef]]s in [[NamedType#withPrefix]] could then
3747+
* result in a [[NoDenotation]], which would make later disambiguation of
3748+
* overloads impossible. See `tests/pos/annot-17242.scala` for example.
3749+
*/
3750+
private class IntegrateMap(from: List[Symbol], to: List[Type])(using Context) extends TypeMap:
3751+
override def apply(tp: Type) =
3752+
// Same implementation as in `SubstMap`, except the `derivedSelect` in
3753+
// the `NamedType` case, and the default case that just calls `mapOver`.
3754+
tp match
3755+
case tp: NamedType =>
3756+
val sym = tp.symbol
3757+
var fs = from
3758+
var ts = to
3759+
while (fs.nonEmpty && ts.nonEmpty) {
3760+
if (fs.head eq sym) return ts.head
3761+
fs = fs.tail
3762+
ts = ts.tail
3763+
}
3764+
if (tp.prefix `eq` NoPrefix) tp
3765+
else derivedSelect(tp, apply(tp.prefix))
3766+
case _: BoundType | _: ThisType => tp
3767+
case _ => mapOver(tp)
3768+
3769+
override final def derivedSelect(tp: NamedType, pre: Type): Type =
3770+
if tp.prefix eq pre then tp
3771+
else if tp.symbol.exists then NamedType(pre, tp.name, tp.denot.asSeenFrom(pre))
3772+
else NamedType(pre, tp.name)
3773+
37363774
final def derivedLambdaType(paramNames: List[ThisName] = this.paramNames,
37373775
paramInfos: List[PInfo] = this.paramInfos,
37383776
resType: Type = this.resType)(using Context): This =
@@ -5939,14 +5977,7 @@ object Types extends TypeUtils {
59395977
}
59405978
}
59415979

5942-
private def treeTypeMap = new TreeTypeMap(
5943-
typeMap = this,
5944-
// Using `ConservativeTreeCopier` is needed when copying dependent annoted
5945-
// types, where we can refer to a previous parameter represented as
5946-
// `TermParamRef` that has no underlying type yet.
5947-
// See tests/pos/annot-17242.scala.
5948-
cpy = ConservativeTreeCopier()
5949-
)
5980+
private def treeTypeMap = new TreeTypeMap(typeMap = this)
59505981

59515982
def mapOver(syms: List[Symbol]): List[Symbol] = mapSymbols(syms, treeTypeMap)
59525983

compiler/src/dotty/tools/dotc/inlines/Inliner.scala

+10-7
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,15 @@ object Inliner:
9696
}
9797
end isElideableExpr
9898

99+
// InlineCopier is a more fault-tolerant copier that does not cause errors when
100+
// function types in applications are undefined. This is necessary since we copy at
101+
// the same time as establishing the proper context in which the copied tree should
102+
// be evaluated. This matters for opaque types, see neg/i14653.scala.
103+
private class InlineCopier() extends TypedTreeCopier:
104+
override def Apply(tree: Tree)(fun: Tree, args: List[Tree])(using Context): Apply =
105+
if fun.tpe.widen.exists then super.Apply(tree)(fun, args)
106+
else untpd.cpy.Apply(tree)(fun, args).withTypeUnchecked(tree.tpe)
107+
99108
// InlinerMap is a TreeTypeMap with special treatment for inlined arguments:
100109
// They are generally left alone (not mapped further, and if they wrap a type
101110
// the type Inlined wrapper gets dropped.
@@ -108,13 +117,7 @@ object Inliner:
108117
substFrom: List[Symbol],
109118
substTo: List[Symbol])(using Context)
110119
extends TreeTypeMap(
111-
typeMap, treeMap, oldOwners, newOwners, substFrom, substTo,
112-
// It is necessary to use the `ConservativeTreeCopier` since we copy at
113-
// the same time as establishing the proper context in which the copied
114-
// tree should be evaluated. This matters for opaque types, see
115-
// neg/i14653.scala.
116-
ConservativeTreeCopier()
117-
):
120+
typeMap, treeMap, oldOwners, newOwners, substFrom, substTo, InlineCopier()):
118121

119122
override def transform(tree: Tree)(using Context): Tree =
120123
tree match

tests/neg/i12448.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
object Main {
22
def mkArray[T <: A]: T#AType // error // error
3-
mkArray[Array] // was: "assertion failed: invalid prefix HKTypeLambda..."
3+
mkArray[Array]
44
val x = mkArray[Array]
55
}

tests/pos/annot-17242.scala

-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
// See also tests/pos/annot-21595.scala
2-
31
class local(predicate: Int) extends annotation.StaticAnnotation
42

53
def failing1(x: Int, z: Int @local(x + x)) = ()

0 commit comments

Comments
 (0)