From 70ecf1aca223fc4e9160a3b359ea2f0d98e0ddcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Doeraene?= Date: Thu, 5 Oct 2023 11:37:19 +0200 Subject: [PATCH] Fix #18649: Use loBound of param types when materializing a context function. Since the param types come from type arguments to `ContextFunctionN[...]`, nothing prevents them a priori from being wildcard type params, i.e., `TypeBounds`. However, that is not a valid type to give to a concrete term param. We can arbitrarily choose any type that conforms to the bounds, which realistically means one of the two bounds. Since type inference already chooses the lower bound when explicitly writing the context function, we align and choose the lower bound when materializing it. [Cherry-picked 242e68f68623b153718ecdc47021f989dfc80f95] --- compiler/src/dotty/tools/dotc/transform/TreeChecker.scala | 8 ++++++++ compiler/src/dotty/tools/dotc/typer/Typer.scala | 2 +- tests/pos/i18649.scala | 7 +++++++ 3 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 tests/pos/i18649.scala diff --git a/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala b/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala index 20290a2ee1f7..b72fcf646aa5 100644 --- a/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala +++ b/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala @@ -571,6 +571,14 @@ object TreeChecker { super.typedClassDef(cdef, cls) } + override def typedValDef(vdef: untpd.ValDef, sym: Symbol)(using Context): Tree = + val tpdTree = super.typedValDef(vdef, sym) + vdef.tpt.tpe match + case _: ValueType => () // ok + case _: ExprType if sym.isOneOf(TermParamOrAccessor) => () // ok + case _ => assert(false, i"wrong type, expected a value type for ${sym.fullName}, but found: ${sym.info}") + tpdTree + override def typedDefDef(ddef: untpd.DefDef, sym: Symbol)(using Context): Tree = def defParamss = ddef.paramss.filter(!_.isEmpty).nestedMap(_.symbol) def layout(symss: List[List[Symbol]]): String = diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index c18a369207a5..13544c32cac2 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -3160,7 +3160,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer val paramTypes = { val hasWildcard = formals.exists(_.existsPart(_.isInstanceOf[WildcardType], StopAt.Static)) if hasWildcard then formals.map(_ => untpd.TypeTree()) - else formals.map(untpd.TypeTree) + else formals.map(formal => untpd.TypeTree(formal.loBound)) // about loBound, see tests/pos/i18649.scala } val erasedParams = pt match { diff --git a/tests/pos/i18649.scala b/tests/pos/i18649.scala new file mode 100644 index 000000000000..d013d5219a1e --- /dev/null +++ b/tests/pos/i18649.scala @@ -0,0 +1,7 @@ +object Test: + // always inferred Nothing for `x` + def contextFunctionWildcardExplicit: ? ?=> String = x ?=> "foo" + + // used to infer TYPEBOUNDS for the type of the argument + def contextFunctionWildcardInserted: ? ?=> String = "foo" +end Test