diff --git a/compiler/src/dotty/tools/dotc/ast/Desugar.scala b/compiler/src/dotty/tools/dotc/ast/Desugar.scala index 59d5be66bc78..3d250d1c33c4 100644 --- a/compiler/src/dotty/tools/dotc/ast/Desugar.scala +++ b/compiler/src/dotty/tools/dotc/ast/Desugar.scala @@ -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 diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 6577c6a12ff3..d8909a981066 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -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) @@ -3039,7 +3040,7 @@ object Parsers { else Nil end recur - recur(firstClause = true, 0) + recur(firstClause = true, numLeadParams) end paramClauses /* -------- DEFS ------------------------------------------- */ @@ -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 = @@ -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") @@ -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 @@ -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) @@ -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 diff --git a/language-server/test/dotty/tools/languageserver/CompletionTest.scala b/language-server/test/dotty/tools/languageserver/CompletionTest.scala index 224025420232..24e9b6e4ea55 100644 --- a/language-server/test/dotty/tools/languageserver/CompletionTest.scala +++ b/language-server/test/dotty/tools/languageserver/CompletionTest.scala @@ -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 }""", @@ -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 = { @@ -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 = { diff --git a/tests/neg/i10901.check b/tests/neg/i10901.check index b11f7952bea7..01a1cc0cdb21 100644 --- a/tests/neg/i10901.check +++ b/tests/neg/i10901.check @@ -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 diff --git a/tests/neg/i6183.check b/tests/neg/i6183.check index 144258bd080a..acb2a58766ec 100644 --- a/tests/neg/i6183.check +++ b/tests/neg/i6183.check @@ -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)) diff --git a/tests/pos/i11020.scala b/tests/pos/i11020.scala new file mode 100644 index 000000000000..077fcdaeeb8e --- /dev/null +++ b/tests/pos/i11020.scala @@ -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) = ??? +