From 242e68f68623b153718ecdc47021f989dfc80f95 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. --- 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 f84f628fc981..2badb4cfc1c3 100644 --- a/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala +++ b/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala @@ -581,6 +581,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 431e863f85d2..bc41fe457ef6 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -3242,7 +3242,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