Skip to content

Commit 1c201a3

Browse files
Merge pull request #14674 from dotty-staging/fix-14653
Tolerate some faults when copying trees in InlineTreeMap
2 parents fe7535f + 8366bad commit 1c201a3

File tree

3 files changed

+31
-2
lines changed

3 files changed

+31
-2
lines changed

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@ class TreeTypeMap(
3737
val oldOwners: List[Symbol] = Nil,
3838
val newOwners: List[Symbol] = Nil,
3939
val substFrom: List[Symbol] = Nil,
40-
val substTo: List[Symbol] = Nil)(using Context) extends tpd.TreeMap {
40+
val substTo: List[Symbol] = Nil,
41+
cpy: tpd.TreeCopier = tpd.cpy)(using Context) extends tpd.TreeMap(cpy) {
4142
import tpd._
4243

4344
def copy(

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

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -903,6 +903,15 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(using Context) {
903903
def inlinedFromOutside(tree: Tree)(span: Span): Tree =
904904
Inlined(EmptyTree, Nil, tree)(using ctx.withSource(inlinedMethod.topLevelClass.source)).withSpan(span)
905905

906+
// InlineCopier is a more fault-tolerant copier that does not cause errors when
907+
// function types in applications are undefined. This is necessary since we copy at
908+
// the same time as establishing the proper context in which the copied tree should
909+
// be evaluated. This matters for opaque types, see neg/i14653.scala.
910+
class InlineCopier() extends TypedTreeCopier:
911+
override def Apply(tree: Tree)(fun: Tree, args: List[Tree])(using Context): Apply =
912+
if fun.tpe.widen.exists then super.Apply(tree)(fun, args)
913+
else untpd.cpy.Apply(tree)(fun, args).withTypeUnchecked(tree.tpe)
914+
906915
// InlinerMap is a TreeTypeMap with special treatment for inlined arguments:
907916
// They are generally left alone (not mapped further, and if they wrap a type
908917
// the type Inlined wrapper gets dropped
@@ -913,7 +922,8 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(using Context) {
913922
newOwners: List[Symbol],
914923
substFrom: List[Symbol],
915924
substTo: List[Symbol])(using Context)
916-
extends TreeTypeMap(typeMap, treeMap, oldOwners, newOwners, substFrom, substTo):
925+
extends TreeTypeMap(
926+
typeMap, treeMap, oldOwners, newOwners, substFrom, substTo, InlineCopier()):
917927

918928
override def copy(
919929
typeMap: Type => Type,

tests/neg/i14653.scala

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
type Amount = Amount.Type
2+
object Amount:
3+
opaque type Type = BigDecimal
4+
inline def apply(inline dec: BigDecimal): Type = dec
5+
6+
extension (self: Type)
7+
inline def value: BigDecimal = self
8+
inline def +(y: Type): Type = self + y
9+
10+
@main def r(): Unit =
11+
val aa: Amount = Amount(1)
12+
val ab: Amount = Amount(2)
13+
val ac: Amount = Amount(2)
14+
val as1: Amount = aa + ab // error
15+
val as2: Amount = aa + ab + ac // error
16+
17+
println(s"aa + ab = ${as1}")
18+
println(s"aa + ab = ${as2}")

0 commit comments

Comments
 (0)