diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 5a3be6505715..98dd5ff0f3f4 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -1534,7 +1534,8 @@ object Parsers { /** Same as [[typ]], but if this results in a wildcard it emits a syntax error and * returns a tree for type `Any` instead. */ - def toplevelTyp(intoOK: IntoOK = IntoOK.No): Tree = rejectWildcardType(typ(intoOK)) + def toplevelTyp(intoOK: IntoOK = IntoOK.No, inContextBound: Boolean = false): Tree = + rejectWildcardType(typ(intoOK, inContextBound)) private def getFunction(tree: Tree): Option[Function] = tree match { case Parens(tree1) => getFunction(tree1) @@ -1594,7 +1595,7 @@ object Parsers { * IntoTargetType ::= Type * | FunTypeArgs (‘=>’ | ‘?=>’) IntoType */ - def typ(intoOK: IntoOK = IntoOK.No): Tree = + def typ(intoOK: IntoOK = IntoOK.No, inContextBound: Boolean = false): Tree = val start = in.offset var imods = Modifiers() val erasedArgs: ListBuffer[Boolean] = ListBuffer() @@ -1743,7 +1744,7 @@ object Parsers { val tuple = atSpan(start): makeTupleOrParens(args.mapConserve(convertToElem)) typeRest: - infixTypeRest: + infixTypeRest(inContextBound): refinedTypeRest: withTypeRest: annotTypeRest: @@ -1772,7 +1773,7 @@ object Parsers { else if isIntoPrefix then PrefixOp(typeIdent(), typ(IntoOK.Nested)) else - typeRest(infixType()) + typeRest(infixType(inContextBound)) end typ private def makeKindProjectorTypeDef(name: TypeName): TypeDef = { @@ -1827,13 +1828,13 @@ object Parsers { /** InfixType ::= RefinedType {id [nl] RefinedType} * | RefinedType `^` // under capture checking */ - def infixType(): Tree = infixTypeRest(refinedType()) + def infixType(inContextBound: Boolean = false): Tree = infixTypeRest(inContextBound)(refinedType()) - def infixTypeRest(t: Tree, operand: Location => Tree = refinedTypeFn): Tree = + def infixTypeRest(inContextBound: Boolean = false)(t: Tree, operand: Location => Tree = refinedTypeFn): Tree = infixOps(t, canStartInfixTypeTokens, operand, Location.ElseWhere, ParseKind.Type, isOperator = !followingIsVararg() && !isPureArrow - && !(isIdent(nme.as) && sourceVersion.isAtLeast(`3.6`)) + && !(isIdent(nme.as) && sourceVersion.isAtLeast(`3.6`) && inContextBound) && nextCanFollowOperator(canStartInfixTypeTokens)) /** RefinedType ::= WithType {[nl] Refinement} [`^` CaptureSet] @@ -2224,7 +2225,7 @@ object Parsers { /** ContextBound ::= Type [`as` id] */ def contextBound(pname: TypeName): Tree = - val t = toplevelTyp() + val t = toplevelTyp(inContextBound = true) val ownName = if isIdent(nme.as) && sourceVersion.isAtLeast(`3.6`) then in.nextToken() @@ -4209,7 +4210,7 @@ object Parsers { else constrApp() match case parent: Apply => parent :: moreConstrApps() case parent if in.isIdent && newSyntaxAllowed => - infixTypeRest(parent, _ => annotType1()) :: Nil + infixTypeRest()(parent, _ => annotType1()) :: Nil case parent => parent :: moreConstrApps() // The term parameters and parent references */ diff --git a/tests/pos/i21769.scala b/tests/pos/i21769.scala new file mode 100644 index 000000000000..afb1c66c97fe --- /dev/null +++ b/tests/pos/i21769.scala @@ -0,0 +1,19 @@ + +infix trait as[From, To] + +val conv: (String as Int) = ??? +given instance: (String as Int) = ??? +def test(ev: (String as Int)) = ??? + +class F + +class K extends (F as K) + +class TC1[X] + +def doSth[X: TC1 as tc] = ??? + +class TC2[X]: + type Self = X + +def doSth2[X: {TC1 as tc1, TC2 as tc2}](x: tc2.Self) = ???