Skip to content

Keep correct track of parameter counts in extension clauses #11079

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jan 19, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/ast/Desugar.scala
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ object desugar {

def addDefaultGetters(meth: DefDef)(using Context): Tree =

/** The longest prefix of parameter lists in =paramss whose total number of
/** The longest prefix of parameter lists in paramss whose total number of
* ValDefs does not exceed `n`
*/
def takeUpTo(paramss: List[ParamClause], n: Int): List[ParamClause] = paramss match
Expand Down
28 changes: 14 additions & 14 deletions compiler/src/dotty/tools/dotc/parsing/Parsers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3020,7 +3020,8 @@ object Parsers {
*/
def paramClauses(ofClass: Boolean = false,
ofCaseClass: Boolean = false,
givenOnly: Boolean = false): List[List[ValDef]] =
givenOnly: Boolean = false,
numLeadParams: Int = 0): List[List[ValDef]] =

def recur(firstClause: Boolean, nparams: Int): List[List[ValDef]] =
newLineOptWhenFollowedBy(LPAREN)
Expand All @@ -3039,7 +3040,7 @@ object Parsers {
else Nil
end recur

recur(firstClause = true, 0)
recur(firstClause = true, numLeadParams)
end paramClauses

/* -------- DEFS ------------------------------------------- */
Expand Down Expand Up @@ -3244,7 +3245,7 @@ object Parsers {
* DefSig ::= id [DefTypeParamClause] DefParamClauses
* | ExtParamClause [nl] [‘.’] id DefParamClauses
*/
def defDefOrDcl(start: Offset, mods: Modifiers): DefDef = atSpan(start, nameStart) {
def defDefOrDcl(start: Offset, mods: Modifiers, numLeadParams: Int = 0): DefDef = atSpan(start, nameStart) {

def scala2ProcedureSyntax(resultTypeStr: String) =
def toInsert =
Expand All @@ -3261,7 +3262,7 @@ object Parsers {

if (in.token == THIS) {
in.nextToken()
val vparamss = paramClauses()
val vparamss = paramClauses(numLeadParams = numLeadParams)
if (vparamss.isEmpty || vparamss.head.take(1).exists(_.mods.isOneOf(GivenOrImplicit)))
in.token match {
case LBRACKET => syntaxError("no type parameters allowed here")
Expand All @@ -3280,7 +3281,7 @@ object Parsers {
val ident = termIdent()
var name = ident.name.asTermName
val tparams = typeParamClauseOpt(ParamOwner.Def)
val vparamss = paramClauses()
val vparamss = paramClauses(numLeadParams = numLeadParams)
var tpt = fromWithinReturnType {
if in.token == COLONEOL then in.token = COLON
// a hack to allow
Expand Down Expand Up @@ -3566,24 +3567,23 @@ object Parsers {
val start = in.skipToken()
val tparams = typeParamClauseOpt(ParamOwner.Def)
val leadParamss = ListBuffer[List[ValDef]]()
var nparams = 0
def nparams = leadParamss.map(_.length).sum
while
val extParams = paramClause(nparams, prefix = true)
leadParamss += extParams
nparams += extParams.length
isUsingClause(extParams)
do ()
leadParamss ++= paramClauses(givenOnly = true)
leadParamss ++= paramClauses(givenOnly = true, numLeadParams = nparams)
if in.token == COLON then
syntaxError("no `:` expected here")
in.nextToken()
val methods =
if isDefIntro(modifierTokens) then
extMethod() :: Nil
extMethod(nparams) :: Nil
else
in.observeIndented()
newLineOptWhenFollowedBy(LBRACE)
if in.isNestedStart then inDefScopeBraces(extMethods())
if in.isNestedStart then inDefScopeBraces(extMethods(nparams))
else { syntaxError("Extension without extension methods"); Nil }
val result = atSpan(start)(ExtMethods(joinParams(tparams, leadParamss.toList), methods))
val comment = in.getDocComment(start)
Expand All @@ -3595,20 +3595,20 @@ object Parsers {

/** ExtMethod ::= {Annotation [nl]} {Modifier} ‘def’ DefDef
*/
def extMethod(): DefDef =
def extMethod(numLeadParams: Int): DefDef =
val start = in.offset
val mods = defAnnotsMods(modifierTokens)
accept(DEF)
defDefOrDcl(start, mods)
defDefOrDcl(start, mods, numLeadParams)

/** ExtMethods ::= ExtMethod | [nl] ‘{’ ExtMethod {semi ExtMethod ‘}’
*/
def extMethods(): List[DefDef] = checkNoEscapingPlaceholders {
def extMethods(numLeadParams: Int): List[DefDef] = checkNoEscapingPlaceholders {
val meths = new ListBuffer[DefDef]
val exitOnError = false
while !isStatSeqEnd && !exitOnError do
setLastStatOffset()
meths += extMethod()
meths += extMethod(numLeadParams)
acceptStatSepUnlessAtEnd(meths)
if meths.isEmpty then syntaxError("`def` expected")
meths.toList
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ class CompletionTest {

// TODO: Also add tests with concrete classes, where the completion will
// include the constructor proxy companion

@Test def importCompleteClassWithPrefix: Unit = {
withSources(
code"""object Foo { abstract class MyClass }""",
Expand Down Expand Up @@ -328,7 +328,7 @@ class CompletionTest {
|given Baz = new Baz {}
|extension (foo: Foo.type)(using Bar, Baz) def xxxx = 1
|object Main { Foo.xx${m1} }""".withSource
.completion(m1, Set(("xxxx", Method, "(using x$1: Bar, x$2: Baz): Int")))
.completion(m1, Set(("xxxx", Method, "(using x$2: Bar, x$3: Baz): Int")))
}

@Test def completeExtensionMethodFromExtenionWithMultipleUsingSections: Unit = {
Expand All @@ -339,7 +339,7 @@ class CompletionTest {
|given Baz = new Baz {}
|extension (foo: Foo.type)(using Bar)(using Baz) def xxxx = 1
|object Main { Foo.xx${m1} }""".withSource
.completion(m1, Set(("xxxx", Method, "(using x$1: Bar)(using x$2: Baz): Int")))
.completion(m1, Set(("xxxx", Method, "(using x$2: Bar)(using x$3: Baz): Int")))
}

@Test def completeInheritedExtensionMethod: Unit = {
Expand Down
2 changes: 1 addition & 1 deletion tests/neg/i10901.check
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,4 @@
|
| Test.foo("abc")(/* missing */summon[C]) failed with
|
| no implicit argument of type C was found for parameter x$1 of method foo in object Test
| no implicit argument of type C was found for parameter x$2 of method foo in object Test
4 changes: 2 additions & 2 deletions tests/neg/i6183.check
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@
| render(42) failed with
|
| Ambiguous overload. The overloaded alternatives of method render in object Test with types
| [B](b: B)(using x$1: DummyImplicit): Char
| [B](b: B)(using x$2: DummyImplicit): Char
| [A](a: A): String
| both match arguments ((42 : Int))
-- [E051] Reference Error: tests/neg/i6183.scala:7:9 -------------------------------------------------------------------
7 | Test.render(42) // error
| ^^^^^^^^^^^
| Ambiguous overload. The overloaded alternatives of method render in object Test with types
| [B](b: B)(using x$1: DummyImplicit): Char
| [B](b: B)(using x$2: DummyImplicit): Char
| [A](a: A): String
| both match arguments ((42 : Int))

Expand Down
7 changes: 7 additions & 0 deletions tests/pos/i11020.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
trait Bar
trait Baz
trait B[X]
extension (using Bar)(s: String)(using Baz) def foo = ???
extension (using Bar)(s: String) def bar(using Baz) = ???
extension [T: B](s: T) def baz [U: B](x: Int) = ???