From fc46e5c0efd8f60e80288d55e9f4fd09dc3061d4 Mon Sep 17 00:00:00 2001 From: odersky Date: Wed, 30 Oct 2024 18:34:09 +0100 Subject: [PATCH] Make sure we don't lose `erased` in method types on Setup --- compiler/src/dotty/tools/dotc/cc/Setup.scala | 5 ++- .../src/dotty/tools/dotc/core/Types.scala | 34 +++++++++++-------- .../captures/erased-methods.scala | 20 +++++++++++ 3 files changed, 43 insertions(+), 16 deletions(-) create mode 100644 tests/pos-custom-args/captures/erased-methods.scala diff --git a/compiler/src/dotty/tools/dotc/cc/Setup.scala b/compiler/src/dotty/tools/dotc/cc/Setup.scala index ddd9e240be5d..665bdb446c86 100644 --- a/compiler/src/dotty/tools/dotc/cc/Setup.scala +++ b/compiler/src/dotty/tools/dotc/cc/Setup.scala @@ -523,13 +523,16 @@ class Setup extends PreRecheck, SymTransformer, SetupAPI: // substitute `x.f.type`, `x` becomes a `TermParamRef`. But the new method // type is still under initialization and `paramInfos` is still `null`, // so the new `NamedType` will not have a denoation. + def adaptedInfo(psym: Symbol, info: mt.PInfo): mt.PInfo = mt.companion match + case mtc: MethodTypeCompanion => mtc.adaptParamInfo(psym, info).asInstanceOf[mt.PInfo] + case _ => info mt.companion(mt.paramNames)( mt1 => if !paramSignatureChanges && !mt.isParamDependent && prevLambdas.isEmpty then mt.paramInfos else val subst = SubstParams(psyms :: prevPsymss, mt1 :: prevLambdas) - psyms.map(psym => subst(psym.nextInfo).asInstanceOf[mt.PInfo]), + psyms.map(psym => adaptedInfo(psym, subst(psym.nextInfo).asInstanceOf[mt.PInfo])), mt1 => integrateRT(mt.resType, psymss.tail, resType, psyms :: prevPsymss, mt1 :: prevLambdas) ) diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 8a9d44cb8d25..ab25d0ae8389 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -4178,24 +4178,28 @@ object Types extends TypeUtils { * - wrap types of parameters that have an @allowConversions annotation with Into[_] */ def fromSymbols(params: List[Symbol], resultType: Type)(using Context): MethodType = + apply(params.map(_.name.asTermName))( + tl => params.map(p => tl.integrate(params, adaptParamInfo(p))), + tl => tl.integrate(params, resultType)) + + /** Adapt info of parameter symbol to be integhrated into corresponding MethodType + * using the scheme described in `fromSymbols`. + */ + def adaptParamInfo(param: Symbol, pinfo: Type)(using Context): Type = def addAnnotation(tp: Type, cls: ClassSymbol, param: Symbol): Type = tp match case ExprType(resType) => ExprType(addAnnotation(resType, cls, param)) case _ => AnnotatedType(tp, Annotation(cls, param.span)) - - def paramInfo(param: Symbol) = - var paramType = param.info - .annotatedToRepeated - .mapIntoAnnot(defn.IntoAnnot, defn.IntoParamAnnot) - if param.is(Inline) then - paramType = addAnnotation(paramType, defn.InlineParamAnnot, param) - if param.is(Erased) then - paramType = addAnnotation(paramType, defn.ErasedParamAnnot, param) - paramType - - apply(params.map(_.name.asTermName))( - tl => params.map(p => tl.integrate(params, paramInfo(p))), - tl => tl.integrate(params, resultType)) - end fromSymbols + var paramType = pinfo + .annotatedToRepeated + .mapIntoAnnot(defn.IntoAnnot, defn.IntoParamAnnot) + if param.is(Inline) then + paramType = addAnnotation(paramType, defn.InlineParamAnnot, param) + if param.is(Erased) then + paramType = addAnnotation(paramType, defn.ErasedParamAnnot, param) + paramType + + def adaptParamInfo(param: Symbol)(using Context): Type = + adaptParamInfo(param, param.info) def apply(paramNames: List[TermName])(paramInfosExp: MethodType => List[Type], resultTypeExp: MethodType => Type)(using Context): MethodType = checkValid(unique(new CachedMethodType(paramNames)(paramInfosExp, resultTypeExp, self))) diff --git a/tests/pos-custom-args/captures/erased-methods.scala b/tests/pos-custom-args/captures/erased-methods.scala new file mode 100644 index 000000000000..911c779e08e5 --- /dev/null +++ b/tests/pos-custom-args/captures/erased-methods.scala @@ -0,0 +1,20 @@ +import language.experimental.saferExceptions +import language.experimental.erasedDefinitions +import language.experimental.captureChecking + +class Ex1 extends Exception("Ex1") +class Ex2 extends Exception("Ex2") +class Ex3 extends Exception("Ex3") + +def foo8a(i: Int) = + (erased xx1: CanThrow[Ex2]^) ?=> throw new Ex2 + +def foo9a(i: Int) + : (erased x$0: CanThrow[Ex3]^) + ?=> (erased x$1: CanThrow[Ex2]^) + ?=> (erased x$2: CanThrow[Ex1]^) + ?=> Unit + = (erased x$1: CanThrow[Ex3]^) + ?=> (erased x$2: CanThrow[Ex2]^) + ?=> (erased x$3: CanThrow[Ex1]^) + ?=> throw new Ex3