diff --git a/compiler/src/dotty/tools/dotc/core/TypeUtils.scala b/compiler/src/dotty/tools/dotc/core/TypeUtils.scala index ca0f0d7e43bd..aca89fa34d1e 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeUtils.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeUtils.scala @@ -8,6 +8,7 @@ import Names.{Name, TermName} import Constants.Constant import Names.Name +import StdNames.nme import config.Feature class TypeUtils: @@ -189,5 +190,25 @@ class TypeUtils: def stripRefinement: Type = self match case self: RefinedOrRecType => self.parent.stripRefinement case seld => self + + def applicableConstructors(argTypes: List[Type], adaptVarargs: Boolean)(using Context): List[Symbol] = + def isApplicable(constr: Symbol): Boolean = + def recur(ctpe: Type): Boolean = ctpe match + case ctpe: PolyType => + if argTypes.isEmpty then recur(ctpe.resultType) // no need to know instances + else recur(ctpe.instantiate(self.argTypes)) + case ctpe: MethodType => + var paramInfos = ctpe.paramInfos + if adaptVarargs && paramInfos.length == argTypes.length + 1 + && atPhaseNoLater(Phases.elimRepeatedPhase)(constr.info.isVarArgsMethod) + then // accept missing argument for varargs parameter + paramInfos = paramInfos.init + argTypes.corresponds(paramInfos)(_ <:< _) + case _ => + false + recur(constr.info) + + self.decl(nme.CONSTRUCTOR).altsWith(isApplicable).map(_.symbol) + end TypeUtils diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 5a9276ae81cc..5ab01aa08a1f 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -5954,27 +5954,17 @@ object Types extends TypeUtils { // `ContextFunctionN` does not have constructors !ctor.exists || zeroParamsOLD(ctor.info) - def zeroParams(tp: Type): Boolean = tp.stripPoly match - case mt: MethodType => - val noArgsNeeded = mt.paramInfos match - case Nil => true - case info :: Nil => info.isRepeatedParam - case _ => false - noArgsNeeded && !mt.resultType.isInstanceOf[MethodType] - case et: ExprType => true - case _ => false def takesNoArgs(tp: Type) = - val constrs = tp.decl(nme.CONSTRUCTOR) - !constrs.exists // `ContextFunctionN` does not have constructors - || constrs.hasAltWith(constr => zeroParams(constr.info)) - def firstParentCls = cls.info.parents.head.classSymbol + !tp.classSymbol.primaryConstructor.exists // `ContextFunctionN` does not have constructors + || tp.applicableConstructors(Nil, adaptVarargs = true).nonEmpty + def firstParentCls = tp.parents.head.classSymbol val noArgsNeeded: Boolean = takesNoArgs(tp) - && (!tp.cls.is(Trait) || takesNoArgs(tp.cls.info.parents.head)) + && (!tp.cls.is(Trait) || takesNoArgs(tp.parents.head)) if noArgsNeeded != validCtorOLD then println( - i"""SAM change for $tp / ${tp.cls.fullName} with parent ${firstParentCls.fullName}, now $noArgsNeeded + i"""SAM change for $tp with parent ${firstParentCls.fullName}, now $noArgsNeeded |takesNoArgs: ${takesNoArgs(tp)} |takesNoArgsParent: ${takesNoArgs(tp.cls.info.parents.head)} |primary: ${firstParentCls.primaryConstructor.info}""")