Skip to content

Commit a062bac

Browse files
authored
Merge pull request #1522 from dotty-staging/fix-#1503
Fix #1503: be more careful where to insert apply
2 parents c420b4c + 440eddd commit a062bac

File tree

9 files changed

+90
-11
lines changed

9 files changed

+90
-11
lines changed

src/dotty/tools/dotc/ast/Desugar.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -699,7 +699,7 @@ object desugar {
699699
Apply(Select(left, op), args)
700700
} else {
701701
val x = ctx.freshName().toTermName
702-
Block(
702+
new InfixOpBlock(
703703
ValDef(x, TypeTree(), left).withMods(synthetic),
704704
Apply(Select(right, op), Ident(x)))
705705
}

src/dotty/tools/dotc/ast/untpd.scala

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,16 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
6363
class PolyTypeDef(name: TypeName, override val tparams: List[TypeDef], rhs: Tree)
6464
extends TypeDef(name, rhs)
6565

66+
/** A block arising from a right-associative infix operation, where, e.g.
67+
*
68+
* a +: b
69+
*
70+
* is expanded to
71+
*
72+
* { val x = a; b.+:(x) }
73+
*/
74+
class InfixOpBlock(leftOperand: Tree, rightOp: Tree) extends Block(leftOperand :: Nil, rightOp)
75+
6676
// ----- TypeTrees that refer to other tree's symbols -------------------
6777

6878
/** A type tree that gets its type from some other tree's symbol. Enters the

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -927,14 +927,17 @@ object Types {
927927
def narrow(implicit ctx: Context): TermRef =
928928
TermRef(NoPrefix, ctx.newSkolem(this))
929929

930-
/** Useful for diagnsotics: The underlying type if this type is a type proxy,
930+
/** Useful for diagnostics: The underlying type if this type is a type proxy,
931931
* otherwise NoType
932932
*/
933933
def underlyingIfProxy(implicit ctx: Context) = this match {
934934
case this1: TypeProxy => this1.underlying
935935
case _ => NoType
936936
}
937937

938+
/** If this is a FunProto or PolyProto, WildcardType, otherwise this. */
939+
def notApplied: Type = this
940+
938941
// ----- Normalizing typerefs over refined types ----------------------------
939942

940943
/** If this normalizes* to a refinement type that has a refinement for `name` (which might be followed

src/dotty/tools/dotc/typer/Applications.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -652,7 +652,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
652652

653653
/** Overridden in ReTyper to handle primitive operations that can be generated after erasure */
654654
protected def handleUnexpectedFunType(tree: untpd.Apply, fun: Tree)(implicit ctx: Context): Tree =
655-
throw new Error(s"unexpected type.\n fun = $fun,\n methPart(fun) = ${methPart(fun)},\n methPart(fun).tpe = ${methPart(fun).tpe},\n tpe = ${fun.tpe}")
655+
throw new Error(i"unexpected type.\n fun = $fun,\n methPart(fun) = ${methPart(fun)},\n methPart(fun).tpe = ${methPart(fun).tpe},\n tpe = ${fun.tpe}")
656656

657657
def typedNamedArgs(args: List[untpd.Tree])(implicit ctx: Context) =
658658
for (arg @ NamedArg(id, argtpt) <- args) yield {

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,8 @@ object ProtoTypes {
182182
if ((args eq this.args) && (resultType eq this.resultType) && (typer eq this.typer)) this
183183
else new FunProto(args, resultType, typer)
184184

185+
override def notApplied = WildcardType
186+
185187
/** Forget the types of any arguments that have been typed producing a constraint in a
186188
* typer state that is not yet committed into the one of the current context `ctx`.
187189
* This is necessary to avoid "orphan" PolyParams that are referred to from
@@ -319,6 +321,8 @@ object ProtoTypes {
319321
if ((targs eq this.targs) && (resType eq this.resType)) this
320322
else PolyProto(targs, resType)
321323

324+
override def notApplied = WildcardType
325+
322326
def map(tm: TypeMap)(implicit ctx: Context): PolyProto =
323327
derivedPolyProto(targs mapConserve tm, tm(resultType))
324328

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

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -572,7 +572,13 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
572572
def typedBlock(tree: untpd.Block, pt: Type)(implicit ctx: Context) = track("typedBlock") {
573573
val exprCtx = index(tree.stats)
574574
val stats1 = typedStats(tree.stats, ctx.owner)
575-
val expr1 = typedExpr(tree.expr, pt)(exprCtx)
575+
val ept =
576+
if (tree.isInstanceOf[untpd.InfixOpBlock])
577+
// Right-binding infix operations are expanded to InfixBlocks, which may be followed by arguments.
578+
// Example: `(a /: bs)(op)` expands to `{ val x = a; bs./:(x) } (op)` where `{...}` is an InfixBlock.
579+
pt
580+
else pt.notApplied
581+
val expr1 = typedExpr(tree.expr, ept)(exprCtx)
576582
ensureNoLocalRefs(
577583
assignType(cpy.Block(tree)(stats1, expr1), stats1, expr1), pt, localSyms(stats1))
578584
}
@@ -619,8 +625,8 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
619625

620626
def typedIf(tree: untpd.If, pt: Type)(implicit ctx: Context) = track("typedIf") {
621627
val cond1 = typed(tree.cond, defn.BooleanType)
622-
val thenp1 = typed(tree.thenp, pt)
623-
val elsep1 = typed(tree.elsep orElse (untpd.unitLiteral withPos tree.pos), pt)
628+
val thenp1 = typed(tree.thenp, pt.notApplied)
629+
val elsep1 = typed(tree.elsep orElse (untpd.unitLiteral withPos tree.pos), pt.notApplied)
624630
val thenp2 :: elsep2 :: Nil = harmonize(thenp1 :: elsep1 :: Nil)
625631
assignType(cpy.If(tree)(cond1, thenp2, elsep2), thenp2, elsep2)
626632
}
@@ -793,7 +799,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
793799
val selType = widenForMatchSelector(
794800
fullyDefinedType(sel1.tpe, "pattern selector", tree.pos))
795801

796-
val cases1 = typedCases(tree.cases, selType, pt)
802+
val cases1 = typedCases(tree.cases, selType, pt.notApplied)
797803
val cases2 = harmonize(cases1).asInstanceOf[List[CaseDef]]
798804
assignType(cpy.Match(tree)(sel1, cases2), cases2)
799805
}
@@ -920,8 +926,8 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
920926
}
921927

922928
def typedTry(tree: untpd.Try, pt: Type)(implicit ctx: Context): Try = track("typedTry") {
923-
val expr1 = typed(tree.expr, pt)
924-
val cases1 = typedCases(tree.cases, defn.ThrowableType, pt)
929+
val expr1 = typed(tree.expr, pt.notApplied)
930+
val cases1 = typedCases(tree.cases, defn.ThrowableType, pt.notApplied)
925931
val finalizer1 = typed(tree.finalizer, defn.UnitType)
926932
val expr2 :: cases2x = harmonize(expr1 :: cases1)
927933
val cases2 = cases2x.asInstanceOf[List[CaseDef]]
@@ -1535,8 +1541,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
15351541
}
15361542

15371543
/** If this tree is a select node `qual.name`, try to insert an implicit conversion
1538-
* `c` around `qual` so that `c(qual).name` conforms to `pt`. If that fails
1539-
* return `tree` itself.
1544+
* `c` around `qual` so that `c(qual).name` conforms to `pt`.
15401545
*/
15411546
def tryInsertImplicitOnQualifier(tree: Tree, pt: Type)(implicit ctx: Context): Option[Tree] = ctx.traceIndented(i"try insert impl on qualifier $tree $pt") {
15421547
tree match {

tests/neg/i1503.scala

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
object Test {
2+
3+
val cond = true
4+
def foo1() = println("hi")
5+
def bar1() = println("there")
6+
7+
def foo2(x: Int) = println("hi")
8+
def bar2(x: Int) = println("there")
9+
10+
def main(args: Array[String]) = {
11+
(if (cond) foo1 else bar1)() // error: Unit does not take parameters
12+
(if (cond) foo2 else bar2)(22) // error: missing arguments // error: missing arguments
13+
}
14+
}

tests/run/i1503.check

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
hello
2+
hi
3+
33
4+
hi
5+
hi

tests/run/i1503.scala

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
object Test {
2+
3+
def test1() =
4+
(new Function0[Unit] {
5+
def apply() = println("hello")
6+
})()
7+
8+
val cond = true
9+
val foo = () => println("hi")
10+
val bar = () => println("there")
11+
12+
val baz = (x: Int) => println(x)
13+
14+
def test2() =
15+
(if (cond) foo else bar)()
16+
17+
def test2a() =
18+
(if (cond) baz else baz)(33)
19+
20+
def test3() =
21+
(try foo
22+
catch { case ex: Exception => bar }
23+
finally ())()
24+
25+
def test4() =
26+
(cond match {
27+
case true => foo
28+
case false => bar
29+
})()
30+
31+
def main(args: Array[String]) = {
32+
test1()
33+
test2()
34+
test2a()
35+
test3()
36+
test4()
37+
}
38+
}

0 commit comments

Comments
 (0)