@@ -1051,49 +1051,74 @@ trait Infer {
10511051 * @param pt the expected result type of the instance
10521052 */
10531053 def inferConstructorInstance (tree : Tree , undetparams : List [Symbol ], pt0 : Type ) {
1054- val pt = widen(pt0)
1055- // println("infer constr inst "+tree+"/"+undetparams+"/"+pt0 )
1056- var restpe = tree.tpe.finalResultType
1057- var tvars = undetparams map freshVar
1054+ val pt = widen(pt0)
1055+ val ptparams = freeTypeParamsOfTerms.collect(pt )
1056+ val ctorTp = tree.tpe
1057+ val resTp = ctorTp.finalResultType
10581058
1059- /** Compute type arguments for undetermined params and substitute them in given tree.
1059+ debuglog(" infer constr inst " + tree + " /" + undetparams + " / pt= " + pt + " pt0= " + pt0 + " resTp: " + resTp)
1060+
1061+ /** Compute type arguments for undetermined params
10601062 */
1061- def computeArgs =
1062- try {
1063- val targs = solvedTypes(tvars, undetparams, undetparams map varianceInType(restpe),
1064- true , lubDepth(List (restpe, pt)))
1065- // checkBounds(tree, NoPrefix, NoSymbol, undetparams, targs, "inferred ")
1066- // no checkBounds here. If we enable it, test bug602 fails.
1067- new TreeTypeSubstituter (undetparams, targs).traverse(tree)
1068- } catch ifNoInstance{ msg =>
1069- NoConstructorInstanceError (tree, restpe, pt, msg)
1063+ def inferFor (pt : Type ): Option [List [Type ]] = {
1064+ val tvars = undetparams map freshVar
1065+ val resTpV = resTp.instantiateTypeParams(undetparams, tvars)
1066+
1067+ if (resTpV <:< pt) {
1068+ try {
1069+ // debuglog("TVARS "+ (tvars map (_.constr)))
1070+ // look at the argument types of the primary constructor corresponding to the pattern
1071+ val variances = undetparams map varianceInType(ctorTp.paramTypes.headOption getOrElse ctorTp)
1072+ val targs = solvedTypes(tvars, undetparams, variances, true , lubDepth(List (resTp, pt)))
1073+ // checkBounds(tree, NoPrefix, NoSymbol, undetparams, targs, "inferred ")
1074+ // no checkBounds here. If we enable it, test bug602 fails.
1075+ // TODO: reinstate checkBounds, return params that fail to meet their bounds to undetparams
1076+ Some (targs)
1077+ } catch ifNoInstance { msg =>
1078+ debuglog(" NO INST " + (tvars, tvars map (_.constr)))
1079+ NoConstructorInstanceError (tree, resTp, pt, msg)
1080+ None
1081+ }
1082+ } else {
1083+ debuglog(" not a subtype: " + resTpV + " </:< " + pt)
1084+ None
10701085 }
1071- def instError = {
1072- if (settings.debug.value) Console .println(" ici " + tree + " " + undetparams + " " + pt)
1073- if (settings.explaintypes.value) explainTypes(restpe.instantiateTypeParams(undetparams, tvars), pt)
1074- ConstrInstantiationError (tree, restpe, pt)
10751086 }
1076- if (restpe.instantiateTypeParams(undetparams, tvars) <:< pt) {
1077- computeArgs
1078- } else if (isFullyDefined(pt)) {
1079- debuglog(" infer constr " + tree + " :" + restpe + " , pt = " + pt)
1080- var ptparams = freeTypeParamsOfTerms.collect(pt)
1081- debuglog(" free type params = " + ptparams)
1082- val ptWithWildcards = pt.instantiateTypeParams(ptparams, ptparams map (ptparam => WildcardType ))
1083- tvars = undetparams map freshVar
1084- if (restpe.instantiateTypeParams(undetparams, tvars) <:< ptWithWildcards) {
1085- computeArgs
1086- restpe = skipImplicit(tree.tpe.resultType)
1087- debuglog(" new tree = " + tree + " :" + restpe)
1088- val ptvars = ptparams map freshVar
1089- val pt1 = pt.instantiateTypeParams(ptparams, ptvars)
1090- if (isPopulated(restpe, pt1)) {
1091- ptvars foreach instantiateTypeVar
1092- } else { if (settings.debug.value) Console .println(" no instance: " ); instError }
1093- } else { if (settings.debug.value) Console .println(" not a subtype " + restpe.instantiateTypeParams(undetparams, tvars) + " of " + ptWithWildcards); instError }
1094- } else { if (settings.debug.value) Console .println(" not fully defined: " + pt); instError }
1087+
1088+ def inferForApproxPt =
1089+ if (isFullyDefined(pt)) {
1090+ inferFor(pt.instantiateTypeParams(ptparams, ptparams map (x => WildcardType ))) flatMap { targs =>
1091+ val ctorTpInst = tree.tpe.instantiateTypeParams(undetparams, targs)
1092+ val resTpInst = skipImplicit(ctorTpInst.finalResultType)
1093+ val ptvars =
1094+ ptparams map {
1095+ // since instantiateTypeVar wants to modify the skolem that corresponds to the method's type parameter,
1096+ // and it uses the TypeVar's origin to locate it, deskolemize the existential skolem to the method tparam skolem
1097+ // (the existential skolem was created by adaptConstrPattern to introduce the type slack necessary to soundly deal with variant type parameters)
1098+ case skolem if skolem.isExistentialSkolem => freshVar(skolem.deSkolemize.asInstanceOf [TypeSymbol ])
1099+ case p => freshVar(p)
1100+ }
1101+
1102+ val ptV = pt.instantiateTypeParams(ptparams, ptvars)
1103+
1104+ if (isPopulated(resTpInst, ptV)) {
1105+ ptvars foreach instantiateTypeVar
1106+ debuglog(" isPopulated " + resTpInst + " , " + ptV + " vars= " + ptvars)
1107+ Some (targs)
1108+ } else None
1109+ }
1110+ } else None
1111+
1112+ (inferFor(pt) orElse inferForApproxPt) map { targs =>
1113+ new TreeTypeSubstituter (undetparams, targs).traverse(tree)
1114+ } getOrElse {
1115+ debugwarn(" failed inferConstructorInstance for " + tree + " : " + tree.tpe + " under " + undetparams + " pt = " + pt + (if (isFullyDefined(pt)) " (fully defined)" else " (not fully defined)" ))
1116+ // if (settings.explaintypes.value) explainTypes(resTp.instantiateTypeParams(undetparams, tvars), pt)
1117+ ConstrInstantiationError (tree, resTp, pt)
1118+ }
10951119 }
10961120
1121+
10971122 def instBounds (tvar : TypeVar ): (Type , Type ) = {
10981123 val tparam = tvar.origin.typeSymbol
10991124 val instType = toOrigin(tvar.constr.inst)
0 commit comments