From b2408dbbf26d1784d97173f009677d9a08a76212 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Marks?= Date: Tue, 2 Mar 2021 10:23:29 +0100 Subject: [PATCH 1/3] Retain position of extension function calls --- compiler/src/dotty/tools/dotc/ast/Trees.scala | 7 ++++ .../src/dotty/tools/dotc/typer/Typer.scala | 2 +- tests/semanticdb/expect/Enums.expect.scala | 2 +- .../semanticdb/expect/Extension.expect.scala | 6 ++++ tests/semanticdb/expect/Extension.scala | 6 ++++ tests/semanticdb/expect/Givens.expect.scala | 6 ++-- tests/semanticdb/metac.expect | 35 ++++++++++++++++--- 7 files changed, 55 insertions(+), 9 deletions(-) create mode 100644 tests/semanticdb/expect/Extension.expect.scala create mode 100644 tests/semanticdb/expect/Extension.scala diff --git a/compiler/src/dotty/tools/dotc/ast/Trees.scala b/compiler/src/dotty/tools/dotc/ast/Trees.scala index 23996ce14dfb..c309daf6ca23 100644 --- a/compiler/src/dotty/tools/dotc/ast/Trees.scala +++ b/compiler/src/dotty/tools/dotc/ast/Trees.scala @@ -415,6 +415,13 @@ object Trees { qualifier.typeOpt.member(name).atSignature(Signature.NotAMethod, name) case _ => super.denot + + def nameSpan(using Context): Span = + if span.exists then + val point = span.point + if span.isSynthetic || name.toTermName == nme.ERROR then Span(point) + else Span(point, span.end, point) + else span } class SelectWithSig[-T >: Untyped] private[ast] (qualifier: Tree[T], name: Name, val sig: Signature)(implicit @constructorOnly src: SourceFile) diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 2a9814ba19d5..48eac6967d74 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -2988,7 +2988,7 @@ class Typer extends Namer def tryExtension(using Context): Tree = findRef(tree.name, WildcardType, ExtensionMethod, EmptyFlags, qual.srcPos) match case ref: TermRef => - extMethodApply(untpd.ref(ref).withSpan(tree.span), qual, pt) + extMethodApply(untpd.TypedSplice(tpd.ref(ref).withSpan(tree.nameSpan)), qual, pt) case _ => EmptyTree diff --git a/tests/semanticdb/expect/Enums.expect.scala b/tests/semanticdb/expect/Enums.expect.scala index cc3630382ba7..aa8f430e173c 100644 --- a/tests/semanticdb/expect/Enums.expect.scala +++ b/tests/semanticdb/expect/Enums.expect.scala @@ -52,7 +52,7 @@ object Enums/*<-_empty_::Enums.*/: extension [A/*<-_empty_::Enums.unwrap().[A]*/, B/*<-_empty_::Enums.unwrap().[B]*/](opt/*<-_empty_::Enums.unwrap().(opt)*/: Option/*->scala::Option#*/[A/*->_empty_::Enums.unwrap().[A]*/]) def unwrap/*<-_empty_::Enums.unwrap().*/(using ev/*<-_empty_::Enums.unwrap().(ev)*/: A/*->_empty_::Enums.unwrap().[A]*/ <:_empty_::Enums.`<:<`#*/ Option/*->scala::Option#*/[B/*->_empty_::Enums.unwrap().[B]*/]): Option/*->scala::Option#*/[B/*->_empty_::Enums.unwrap().[B]*/] = ev/*->_empty_::Enums.unwrap().(ev)*/ match case Refl/*->_empty_::Enums.`<:<`.Refl.*//*->_empty_::Enums.`<:<`.Refl.unapply().*/() => opt/*->_empty_::Enums.unwrap().(opt)*/.flatMap/*->scala::Option#flatMap().*/(identity/*->scala::Predef.identity().*//*->local0*/[Option/*->scala::Option#*/[B/*->_empty_::Enums.unwrap().[B]*/]]) - val some1/*<-_empty_::Enums.some1.*/ = /*->_empty_::Enums.unwrap().*/Some/*->scala::Some.*//*->scala::Some.apply().*/(Some/*->scala::Some.*//*->scala::Some.apply().*/(1)).unwrap/*->_empty_::Enums.`<:<`.given_T().*/ + val some1/*<-_empty_::Enums.some1.*/ = Some/*->scala::Some.*//*->scala::Some.apply().*/(Some/*->scala::Some.*//*->scala::Some.apply().*/(1)).unwrap/*->_empty_::Enums.unwrap().*//*->_empty_::Enums.`<:<`.given_T().*/ enum Planet/*<-_empty_::Enums.Planet#*/(mass/*<-_empty_::Enums.Planet#mass.*/: Double/*->scala::Double#*/, radius/*<-_empty_::Enums.Planet#radius.*/: Double/*->scala::Double#*/) extends Enum/*->java::lang::Enum#*/[Planet/*->_empty_::Enums.Planet#*/]/*->java::lang::Enum#``().*/: private final val G/*<-_empty_::Enums.Planet#G.*/ = 6.67300E-11 diff --git a/tests/semanticdb/expect/Extension.expect.scala b/tests/semanticdb/expect/Extension.expect.scala new file mode 100644 index 000000000000..556e7f735b62 --- /dev/null +++ b/tests/semanticdb/expect/Extension.expect.scala @@ -0,0 +1,6 @@ +package ext + +/*<-ext::Extension$package.*/extension (s/*<-ext::Extension$package.foo().(s)*/: String/*->scala::Predef.String#*/) + def foo/*<-ext::Extension$package.foo().*/: Int/*->scala::Int#*/ = 42 + +val a/*<-ext::Extension$package.a.*/ = "asd".foo/*->ext::Extension$package.foo().*/ \ No newline at end of file diff --git a/tests/semanticdb/expect/Extension.scala b/tests/semanticdb/expect/Extension.scala new file mode 100644 index 000000000000..859227211ea7 --- /dev/null +++ b/tests/semanticdb/expect/Extension.scala @@ -0,0 +1,6 @@ +package ext + +extension (s: String) + def foo: Int = 42 + +val a = "asd".foo \ No newline at end of file diff --git a/tests/semanticdb/expect/Givens.expect.scala b/tests/semanticdb/expect/Givens.expect.scala index 126c1f8e9919..35ef1d7c3cf9 100644 --- a/tests/semanticdb/expect/Givens.expect.scala +++ b/tests/semanticdb/expect/Givens.expect.scala @@ -10,9 +10,9 @@ object Givens/*<-a::b::Givens.*/: def sayGoodbye/*<-a::b::Givens.sayGoodbye().*/ = s"/*->scala::StringContext.apply().*/Goodbye, from $any/*->a::b::Givens.sayGoodbye().(any)*/"/*->scala::StringContext#s().*/ def saySoLong/*<-a::b::Givens.saySoLong().*/ = s"/*->scala::StringContext.apply().*/So Long, from $any/*->a::b::Givens.saySoLong().(any)*/"/*->scala::StringContext#s().*/ - val hello1/*<-a::b::Givens.hello1.*/ = /*->a::b::Givens.sayHello().*/1.sayHello - val goodbye1/*<-a::b::Givens.goodbye1.*/ = /*->a::b::Givens.sayGoodbye().*/1.sayGoodbye - val soLong1/*<-a::b::Givens.soLong1.*/ = /*->a::b::Givens.saySoLong().*/1.saySoLong + val hello1/*<-a::b::Givens.hello1.*/ = 1.sayHello/*->a::b::Givens.sayHello().*/ + val goodbye1/*<-a::b::Givens.goodbye1.*/ = 1.sayGoodbye/*->a::b::Givens.sayGoodbye().*/ + val soLong1/*<-a::b::Givens.soLong1.*/ = 1.saySoLong/*->a::b::Givens.saySoLong().*/ trait Monoid/*<-a::b::Givens.Monoid#*/[A/*<-a::b::Givens.Monoid#[A]*/]: def empty/*<-a::b::Givens.Monoid#empty().*/: A/*->a::b::Givens.Monoid#[A]*/ diff --git a/tests/semanticdb/metac.expect b/tests/semanticdb/metac.expect index 191e2f3d0379..245176fb11c8 100644 --- a/tests/semanticdb/metac.expect +++ b/tests/semanticdb/metac.expect @@ -966,11 +966,11 @@ Occurrences: [52:40..52:46): Option -> scala/Option# [52:47..52:48): B -> _empty_/Enums.unwrap().[B] [54:6..54:11): some1 <- _empty_/Enums.some1. -[54:14..54:14): -> _empty_/Enums.unwrap(). [54:14..54:18): Some -> scala/Some. [54:18..54:18): -> scala/Some.apply(). [54:19..54:23): Some -> scala/Some. [54:23..54:23): -> scala/Some.apply(). +[54:28..54:34): unwrap -> _empty_/Enums.unwrap(). [54:34..54:34): -> _empty_/Enums.`<:<`.given_T(). [56:7..56:13): Planet <- _empty_/Enums.Planet# [56:13..56:13): <- _empty_/Enums.Planet#``(). @@ -1104,6 +1104,33 @@ Occurrences: [9:33..9:36): Int -> scala/Int# [9:37..9:37): -> scala/reflect/ClassTag.apply(). +expect/Extension.scala +---------------------- + +Summary: +Schema => SemanticDB v4 +Uri => Extension.scala +Text => empty +Language => Scala +Symbols => 4 entries +Occurrences => 8 entries + +Symbols: +ext/Extension$package. => final package object ext +ext/Extension$package.a. => val method a +ext/Extension$package.foo(). => method foo +ext/Extension$package.foo().(s) => param s + +Occurrences: +[0:8..0:11): ext <- ext/ +[2:0..2:0): <- ext/Extension$package. +[2:11..2:12): s <- ext/Extension$package.foo().(s) +[2:14..2:20): String -> scala/Predef.String# +[3:6..3:9): foo <- ext/Extension$package.foo(). +[3:11..3:14): Int -> scala/Int# +[5:4..5:5): a <- ext/Extension$package.a. +[5:14..5:17): foo -> ext/Extension$package.foo(). + expect/ForComprehension.scala ----------------------------- @@ -1288,11 +1315,11 @@ Occurrences: [10:37..10:40): any -> a/b/Givens.saySoLong().(any) [10:40..10:41): " -> scala/StringContext#s(). [12:6..12:12): hello1 <- a/b/Givens.hello1. -[12:15..12:15): -> a/b/Givens.sayHello(). +[12:17..12:25): sayHello -> a/b/Givens.sayHello(). [13:6..13:14): goodbye1 <- a/b/Givens.goodbye1. -[13:17..13:17): -> a/b/Givens.sayGoodbye(). +[13:19..13:29): sayGoodbye -> a/b/Givens.sayGoodbye(). [14:6..14:13): soLong1 <- a/b/Givens.soLong1. -[14:16..14:16): -> a/b/Givens.saySoLong(). +[14:18..14:27): saySoLong -> a/b/Givens.saySoLong(). [16:8..16:14): Monoid <- a/b/Givens.Monoid# [16:14..16:14): <- a/b/Givens.Monoid#``(). [16:15..16:16): A <- a/b/Givens.Monoid#[A] From e93460b44a6bc50211d76ae003539e64b1ae7f6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Marks?= Date: Thu, 4 Mar 2021 20:37:50 +0100 Subject: [PATCH 2/3] Retain positions of operators after desugaring --- .../src/dotty/tools/dotc/ast/Desugar.scala | 5 ++- compiler/src/dotty/tools/dotc/ast/Trees.scala | 6 ++-- .../RightAssociativeExtension.expect.scala | 6 ++++ .../expect/RightAssociativeExtension.scala | 6 ++++ tests/semanticdb/metac.expect | 34 +++++++++++++++++++ 5 files changed, 54 insertions(+), 3 deletions(-) create mode 100644 tests/semanticdb/expect/RightAssociativeExtension.expect.scala create mode 100644 tests/semanticdb/expect/RightAssociativeExtension.scala diff --git a/compiler/src/dotty/tools/dotc/ast/Desugar.scala b/compiler/src/dotty/tools/dotc/ast/Desugar.scala index c7b462ca6c5f..d50f03f135a0 100644 --- a/compiler/src/dotty/tools/dotc/ast/Desugar.scala +++ b/compiler/src/dotty/tools/dotc/ast/Desugar.scala @@ -39,6 +39,9 @@ object desugar { */ val MultiLineInfix: Property.Key[Unit] = Property.StickyKey() + /** An attachment for retaining information about the original span of the operator after desugaring it to Select. */ + val OperatorSpan: Property.Key[Span] = Property.StickyKey() + /** What static check should be applied to a Match? */ enum MatchCheck { case None, Exhaustive, IrrefutablePatDef, IrrefutableGenFrom @@ -1215,7 +1218,7 @@ object desugar { case _ => arg } def makeOp(fn: Tree, arg: Tree, selectPos: Span) = - val sel = Select(fn, op.name).withSpan(selectPos) + val sel = Select(fn, op.name).withSpan(selectPos).withAttachment(OperatorSpan, op.span) if (left.sourcePos.endLine < op.sourcePos.startLine) sel.pushAttachment(MultiLineInfix, ()) arg match diff --git a/compiler/src/dotty/tools/dotc/ast/Trees.scala b/compiler/src/dotty/tools/dotc/ast/Trees.scala index c309daf6ca23..08730a51a546 100644 --- a/compiler/src/dotty/tools/dotc/ast/Trees.scala +++ b/compiler/src/dotty/tools/dotc/ast/Trees.scala @@ -419,8 +419,10 @@ object Trees { def nameSpan(using Context): Span = if span.exists then val point = span.point - if span.isSynthetic || name.toTermName == nme.ERROR then Span(point) - else Span(point, span.end, point) + getAttachment(desugar.OperatorSpan) match + case Some(s) => s + case None if span.isSynthetic || name.toTermName == nme.ERROR => Span(point) + case None => Span(point, span.end, point) else span } diff --git a/tests/semanticdb/expect/RightAssociativeExtension.expect.scala b/tests/semanticdb/expect/RightAssociativeExtension.expect.scala new file mode 100644 index 000000000000..38f81d0154ef --- /dev/null +++ b/tests/semanticdb/expect/RightAssociativeExtension.expect.scala @@ -0,0 +1,6 @@ +package ext + +/*<-ext::RightAssociativeExtension$package.*/extension (s/*<-ext::RightAssociativeExtension$package.`:*:`().(s)*/: String/*->scala::Predef.String#*/) + def :*:/*<-ext::RightAssociativeExtension$package.`:*:`().*/ (i/*<-ext::RightAssociativeExtension$package.`:*:`().(i)*/: Int/*->scala::Int#*/): (String/*->scala::Predef.String#*/, Int/*->scala::Int#*/) = (/*->scala::Tuple2.apply().*/s/*->ext::RightAssociativeExtension$package.`:*:`().(s)*/, i/*->ext::RightAssociativeExtension$package.`:*:`().(i)*/) + +val b/*<-ext::RightAssociativeExtension$package.b.*/ = "foo" :*:/*->ext::RightAssociativeExtension$package.`:*:`().*/ 23 \ No newline at end of file diff --git a/tests/semanticdb/expect/RightAssociativeExtension.scala b/tests/semanticdb/expect/RightAssociativeExtension.scala new file mode 100644 index 000000000000..680dba16fc3c --- /dev/null +++ b/tests/semanticdb/expect/RightAssociativeExtension.scala @@ -0,0 +1,6 @@ +package ext + +extension (s: String) + def :*: (i: Int): (String, Int) = (s, i) + +val b = "foo" :*: 23 \ No newline at end of file diff --git a/tests/semanticdb/metac.expect b/tests/semanticdb/metac.expect index 245176fb11c8..1c27f41754a0 100644 --- a/tests/semanticdb/metac.expect +++ b/tests/semanticdb/metac.expect @@ -2415,6 +2415,40 @@ Occurrences: [31:10..31:11): T -> prefixes/M.T# [31:14..31:17): ??? -> scala/Predef.`???`(). +expect/RightAssociativeExtension.scala +-------------------------------------- + +Summary: +Schema => SemanticDB v4 +Uri => RightAssociativeExtension.scala +Text => empty +Language => Scala +Symbols => 5 entries +Occurrences => 14 entries + +Symbols: +ext/RightAssociativeExtension$package. => final package object ext +ext/RightAssociativeExtension$package.`:*:`(). => method :*: +ext/RightAssociativeExtension$package.`:*:`().(i) => param i +ext/RightAssociativeExtension$package.`:*:`().(s) => param s +ext/RightAssociativeExtension$package.b. => val method b + +Occurrences: +[0:8..0:11): ext <- ext/ +[2:0..2:0): <- ext/RightAssociativeExtension$package. +[2:11..2:12): s <- ext/RightAssociativeExtension$package.`:*:`().(s) +[2:14..2:20): String -> scala/Predef.String# +[3:6..3:9): :*: <- ext/RightAssociativeExtension$package.`:*:`(). +[3:11..3:12): i <- ext/RightAssociativeExtension$package.`:*:`().(i) +[3:14..3:17): Int -> scala/Int# +[3:21..3:27): String -> scala/Predef.String# +[3:29..3:32): Int -> scala/Int# +[3:37..3:37): -> scala/Tuple2.apply(). +[3:37..3:38): s -> ext/RightAssociativeExtension$package.`:*:`().(s) +[3:40..3:41): i -> ext/RightAssociativeExtension$package.`:*:`().(i) +[5:4..5:5): b <- ext/RightAssociativeExtension$package.b. +[5:14..5:17): :*: -> ext/RightAssociativeExtension$package.`:*:`(). + expect/Selfs.scala ------------------ From a1b5b77612899e48057be8716f1c0a7366637ff4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Marks?= Date: Fri, 5 Mar 2021 10:57:28 +0100 Subject: [PATCH 3/3] Remove operator position attachment - simplify select name span logic - add test for left associative operators --- .../src/dotty/tools/dotc/ast/Desugar.scala | 5 +--- compiler/src/dotty/tools/dotc/ast/Trees.scala | 11 +++++---- .../semanticdb/expect/Extension.expect.scala | 7 ++++-- tests/semanticdb/expect/Extension.scala | 5 +++- tests/semanticdb/metac.expect | 23 +++++++++++++++---- 5 files changed, 36 insertions(+), 15 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/ast/Desugar.scala b/compiler/src/dotty/tools/dotc/ast/Desugar.scala index d50f03f135a0..c7b462ca6c5f 100644 --- a/compiler/src/dotty/tools/dotc/ast/Desugar.scala +++ b/compiler/src/dotty/tools/dotc/ast/Desugar.scala @@ -39,9 +39,6 @@ object desugar { */ val MultiLineInfix: Property.Key[Unit] = Property.StickyKey() - /** An attachment for retaining information about the original span of the operator after desugaring it to Select. */ - val OperatorSpan: Property.Key[Span] = Property.StickyKey() - /** What static check should be applied to a Match? */ enum MatchCheck { case None, Exhaustive, IrrefutablePatDef, IrrefutableGenFrom @@ -1218,7 +1215,7 @@ object desugar { case _ => arg } def makeOp(fn: Tree, arg: Tree, selectPos: Span) = - val sel = Select(fn, op.name).withSpan(selectPos).withAttachment(OperatorSpan, op.span) + val sel = Select(fn, op.name).withSpan(selectPos) if (left.sourcePos.endLine < op.sourcePos.startLine) sel.pushAttachment(MultiLineInfix, ()) arg match diff --git a/compiler/src/dotty/tools/dotc/ast/Trees.scala b/compiler/src/dotty/tools/dotc/ast/Trees.scala index 08730a51a546..7135df4b88a1 100644 --- a/compiler/src/dotty/tools/dotc/ast/Trees.scala +++ b/compiler/src/dotty/tools/dotc/ast/Trees.scala @@ -419,10 +419,13 @@ object Trees { def nameSpan(using Context): Span = if span.exists then val point = span.point - getAttachment(desugar.OperatorSpan) match - case Some(s) => s - case None if span.isSynthetic || name.toTermName == nme.ERROR => Span(point) - case None => Span(point, span.end, point) + if name.toTermName == nme.ERROR then + Span(point) + else if qualifier.span.start > span.start then // right associative + val realName = name.stripModuleClassSuffix.lastPart + Span(span.start, span.start + realName.length, point) + else + Span(point, span.end, point) else span } diff --git a/tests/semanticdb/expect/Extension.expect.scala b/tests/semanticdb/expect/Extension.expect.scala index 556e7f735b62..d96dcd4c87c8 100644 --- a/tests/semanticdb/expect/Extension.expect.scala +++ b/tests/semanticdb/expect/Extension.expect.scala @@ -1,6 +1,9 @@ package ext -/*<-ext::Extension$package.*/extension (s/*<-ext::Extension$package.foo().(s)*/: String/*->scala::Predef.String#*/) +/*<-ext::Extension$package.*/extension (s/*<-ext::Extension$package.foo().(s)*//*<-ext::Extension$package.`#*#`().(s)*/: String/*->scala::Predef.String#*/) def foo/*<-ext::Extension$package.foo().*/: Int/*->scala::Int#*/ = 42 + def #*#/*<-ext::Extension$package.`#*#`().*/ (i/*<-ext::Extension$package.`#*#`().(i)*/: Int/*->scala::Int#*/): (String/*->scala::Predef.String#*/, Int/*->scala::Int#*/) = (/*->scala::Tuple2.apply().*/s/*->ext::Extension$package.`#*#`().(s)*/, i/*->ext::Extension$package.`#*#`().(i)*/) -val a/*<-ext::Extension$package.a.*/ = "asd".foo/*->ext::Extension$package.foo().*/ \ No newline at end of file +val a/*<-ext::Extension$package.a.*/ = "asd".foo/*->ext::Extension$package.foo().*/ + +val c/*<-ext::Extension$package.c.*/ = "foo" #*#/*->ext::Extension$package.`#*#`().*/ 23 \ No newline at end of file diff --git a/tests/semanticdb/expect/Extension.scala b/tests/semanticdb/expect/Extension.scala index 859227211ea7..5b9c3e5f21ab 100644 --- a/tests/semanticdb/expect/Extension.scala +++ b/tests/semanticdb/expect/Extension.scala @@ -2,5 +2,8 @@ package ext extension (s: String) def foo: Int = 42 + def #*# (i: Int): (String, Int) = (s, i) -val a = "asd".foo \ No newline at end of file +val a = "asd".foo + +val c = "foo" #*# 23 \ No newline at end of file diff --git a/tests/semanticdb/metac.expect b/tests/semanticdb/metac.expect index 1c27f41754a0..79ffcf7125fc 100644 --- a/tests/semanticdb/metac.expect +++ b/tests/semanticdb/metac.expect @@ -1112,12 +1112,16 @@ Schema => SemanticDB v4 Uri => Extension.scala Text => empty Language => Scala -Symbols => 4 entries -Occurrences => 8 entries +Symbols => 8 entries +Occurrences => 19 entries Symbols: ext/Extension$package. => final package object ext +ext/Extension$package.`#*#`(). => method #*# +ext/Extension$package.`#*#`().(i) => param i +ext/Extension$package.`#*#`().(s) => param s ext/Extension$package.a. => val method a +ext/Extension$package.c. => val method c ext/Extension$package.foo(). => method foo ext/Extension$package.foo().(s) => param s @@ -1125,11 +1129,22 @@ Occurrences: [0:8..0:11): ext <- ext/ [2:0..2:0): <- ext/Extension$package. [2:11..2:12): s <- ext/Extension$package.foo().(s) +[2:11..2:12): s <- ext/Extension$package.`#*#`().(s) [2:14..2:20): String -> scala/Predef.String# [3:6..3:9): foo <- ext/Extension$package.foo(). [3:11..3:14): Int -> scala/Int# -[5:4..5:5): a <- ext/Extension$package.a. -[5:14..5:17): foo -> ext/Extension$package.foo(). +[4:6..4:9): #*# <- ext/Extension$package.`#*#`(). +[4:11..4:12): i <- ext/Extension$package.`#*#`().(i) +[4:14..4:17): Int -> scala/Int# +[4:21..4:27): String -> scala/Predef.String# +[4:29..4:32): Int -> scala/Int# +[4:37..4:37): -> scala/Tuple2.apply(). +[4:37..4:38): s -> ext/Extension$package.`#*#`().(s) +[4:40..4:41): i -> ext/Extension$package.`#*#`().(i) +[6:4..6:5): a <- ext/Extension$package.a. +[6:14..6:17): foo -> ext/Extension$package.foo(). +[8:4..8:5): c <- ext/Extension$package.c. +[8:14..8:17): #*# -> ext/Extension$package.`#*#`(). expect/ForComprehension.scala -----------------------------