Skip to content

Commit

Permalink
Merge pull request #14674 from dotty-staging/fix-14653
Browse files Browse the repository at this point in the history
Tolerate some faults when copying trees in InlineTreeMap
  • Loading branch information
nicolasstucki authored Mar 15, 2022
2 parents fe7535f + 8366bad commit 1c201a3
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 2 deletions.
3 changes: 2 additions & 1 deletion compiler/src/dotty/tools/dotc/ast/TreeTypeMap.scala
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ class TreeTypeMap(
val oldOwners: List[Symbol] = Nil,
val newOwners: List[Symbol] = Nil,
val substFrom: List[Symbol] = Nil,
val substTo: List[Symbol] = Nil)(using Context) extends tpd.TreeMap {
val substTo: List[Symbol] = Nil,
cpy: tpd.TreeCopier = tpd.cpy)(using Context) extends tpd.TreeMap(cpy) {
import tpd._

def copy(
Expand Down
12 changes: 11 additions & 1 deletion compiler/src/dotty/tools/dotc/typer/Inliner.scala
Original file line number Diff line number Diff line change
Expand Up @@ -903,6 +903,15 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(using Context) {
def inlinedFromOutside(tree: Tree)(span: Span): Tree =
Inlined(EmptyTree, Nil, tree)(using ctx.withSource(inlinedMethod.topLevelClass.source)).withSpan(span)

// InlineCopier is a more fault-tolerant copier that does not cause errors when
// function types in applications are undefined. This is necessary since we copy at
// the same time as establishing the proper context in which the copied tree should
// be evaluated. This matters for opaque types, see neg/i14653.scala.
class InlineCopier() extends TypedTreeCopier:
override def Apply(tree: Tree)(fun: Tree, args: List[Tree])(using Context): Apply =
if fun.tpe.widen.exists then super.Apply(tree)(fun, args)
else untpd.cpy.Apply(tree)(fun, args).withTypeUnchecked(tree.tpe)

// InlinerMap is a TreeTypeMap with special treatment for inlined arguments:
// They are generally left alone (not mapped further, and if they wrap a type
// the type Inlined wrapper gets dropped
Expand All @@ -913,7 +922,8 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(using Context) {
newOwners: List[Symbol],
substFrom: List[Symbol],
substTo: List[Symbol])(using Context)
extends TreeTypeMap(typeMap, treeMap, oldOwners, newOwners, substFrom, substTo):
extends TreeTypeMap(
typeMap, treeMap, oldOwners, newOwners, substFrom, substTo, InlineCopier()):

override def copy(
typeMap: Type => Type,
Expand Down
18 changes: 18 additions & 0 deletions tests/neg/i14653.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
type Amount = Amount.Type
object Amount:
opaque type Type = BigDecimal
inline def apply(inline dec: BigDecimal): Type = dec

extension (self: Type)
inline def value: BigDecimal = self
inline def +(y: Type): Type = self + y

@main def r(): Unit =
val aa: Amount = Amount(1)
val ab: Amount = Amount(2)
val ac: Amount = Amount(2)
val as1: Amount = aa + ab // error
val as2: Amount = aa + ab + ac // error

println(s"aa + ab = ${as1}")
println(s"aa + ab = ${as2}")

0 comments on commit 1c201a3

Please sign in to comment.