diff options
author | Adriaan Moors <adriaan.moors@epfl.ch> | 2010-09-16 22:26:24 +0000 |
---|---|---|
committer | Adriaan Moors <adriaan.moors@epfl.ch> | 2010-09-16 22:26:24 +0000 |
commit | e557acb9a7d672c0635c3eaf9fe385adc41e5c86 (patch) | |
tree | d13db6639464acc57f0e44b4b3ef6f3e607ad403 /src/compiler | |
parent | ce223fe7abc47af712382a64404604e75f9f4d20 (diff) | |
download | scala-e557acb9a7d672c0635c3eaf9fe385adc41e5c86.tar.gz scala-e557acb9a7d672c0635c3eaf9fe385adc41e5c86.tar.bz2 scala-e557acb9a7d672c0635c3eaf9fe385adc41e5c86.zip |
part 2 of the dependent method refactoring: imp...
part 2 of the dependent method refactoring: improved interaction with
implicit search (needed for oopsla paper)
more to come in this area, see e.g. #3346 (stanford edsl stuff)
reopens #13, which wasn't fixed properly before imo, anyway (have a look at -Xprint:typer output before this commit: a type that's not expressible in surface syntax is inferred -- also removed duplicate test file)
closes #3731: co-evolve type alias type symbols when their rhs is
updated and they are referenced by type selections (see typemap)
review by odersky
Diffstat (limited to 'src/compiler')
4 files changed, 202 insertions, 76 deletions
diff --git a/src/compiler/scala/tools/nsc/symtab/Types.scala b/src/compiler/scala/tools/nsc/symtab/Types.scala index f17b33aa5a..19665715b5 100644 --- a/src/compiler/scala/tools/nsc/symtab/Types.scala +++ b/src/compiler/scala/tools/nsc/symtab/Types.scala @@ -807,12 +807,18 @@ trait Types extends reflect.generic.Types { self: SymbolTable => */ //TODO: use narrow only for modules? (correct? efficiency gain?) def findMember(name: Name, excludedFlags: Long, requiredFlags: Long, stableOnly: Boolean): Symbol = { - // if this type contains type variables, get rid of them; + val suspension = TypeVar.Suspension + // if this type contains type variables, put them to sleep for a while -- don't just wipe them out by + // replacing them by the corresponding type parameter, as that messes up (e.g.) type variables in type refinements // without this, the matchesType call would lead to type variables on both sides // of a subtyping/equality judgement, which can lead to recursive types being constructed. // See (t0851) for a situation where this happens. - if (!this.isGround) - return typeVarToOriginMap(this).findMember(name, excludedFlags, requiredFlags, stableOnly) + if (!this.isGround) { + // make each type var in this type use its original type for comparisons instead of collecting constraints + for(tv@TypeVar(_, _) <- this) { + suspension suspend tv + } + } incCounter(findMemberCount) val start = startTimer(findMemberNanos) @@ -843,6 +849,7 @@ trait Types extends reflect.generic.Types { self: SymbolTable => (bcs0.head.hasTransOwner(bcs.head)))) { if (name.isTypeName || stableOnly && sym.isStable) { stopTimer(findMemberNanos, start) + suspension.resumeAll return sym } else if (member == NoSymbol) { member = sym @@ -884,6 +891,7 @@ trait Types extends reflect.generic.Types { self: SymbolTable => excluded = excludedFlags } // while (continue) stopTimer(findMemberNanos, start) + suspension.resumeAll if (members eq null) { if (member == NoSymbol) incCounter(noMemberCount) member @@ -1729,32 +1737,41 @@ A type's typeSymbol should never be inspected directly. private var normalized: Type = null + @inline private def betaReduce: Type = { + assert(sym.info.typeParams.length == typeArgs.length, this) + // isHKSubType0 introduces synthetic type params so that betaReduce can first apply sym.info to typeArgs before calling asSeenFrom + // asSeenFrom then skips synthetic type params, which are used to reduce HO subtyping to first-order subtyping, but which can't be instantiated from the given prefix and class + // appliedType(sym.info, typeArgs).asSeenFrom(pre, sym.owner) // this crashes pos/depmet_implicit_tpbetareduce.scala + transform(sym.info.resultType) + } + + // @M TODO: should not use PolyType, as that's the type of a polymorphic value -- we really want a type *function* + // @M: initialize (by sym.info call) needed (see test/files/pos/ticket0137.scala) + @inline private def etaExpand: Type = { + val tpars = sym.info.typeParams // must go through sym.info for typeParams to initialise symbol + PolyType(tpars, typeRef(pre, sym, tpars map (_.tpeHK))) // todo: also beta-reduce? + } + override def dealias: Type = if (sym.isAliasType && sym.info.typeParams.length == args.length) { - val xform = transform(sym.info.resultType) - assert(xform ne this, this) - xform.dealias + betaReduce.dealias } else this - override def remove(clazz: Symbol): Type = - if (sym == clazz && !args.isEmpty) args.head else this - def normalize0: Type = - if (isHigherKinded) { - // @M TODO: should not use PolyType, as that's the type of a polymorphic value -- we really want a type *function* - // @M: initialize (by sym.info call) needed (see test/files/pos/ticket0137.scala) - PolyType(sym.info.typeParams, typeRef(pre, sym, dummyArgs)) // must go through sym.info for typeParams - } else if (sym.isAliasType) { // beta-reduce - if(sym.info.typeParams.length == args.length) // don't do partial application - transform(sym.info.resultType).normalize // cycles have been checked in typeRef - else - ErrorType - } else if (sym.isRefinementClass) { - sym.info.normalize // @MO to AM: OK? - //@M I think this is okay, but changeset 12414 (which fixed #1241) re-introduced another bug (#2208) - // see typedTypeConstructor in Typers - } else { - super.normalize + if (pre eq WildcardType) WildcardType // arises when argument-dependent types are approximated (see def depoly in implicits) + else if (isHigherKinded) etaExpand // eta-expand, subtyping relies on eta-expansion of higher-kinded types + else if (sym.isAliasType && sym.info.typeParams.length == args.length) + betaReduce.normalize // beta-reduce, but don't do partial application -- cycles have been checked in typeRef + else if (sym.isRefinementClass) + sym.info.normalize // I think this is okay, but see #1241 (r12414), #2208, and typedTypeConstructor in Typers + // else if (args nonEmpty) { + // val argsNorm = args mapConserve (_.dealias) + // if(argsNorm ne args) TypeRef(pre, sym, argsNorm) + // else this + // } + else { + if(sym.isAliasType) ErrorType //println("!!error: "+(pre, sym, sym.info, sym.info.typeParams, args)) + else super.normalize } // track number of type parameters that we saw when caching normalization, @@ -2165,6 +2182,22 @@ A type's typeSymbol should never be inspected directly. // then, constr became mutable (to support UndoLog, I guess), but pattern-matching returned the original constr0 (a bug) // now, pattern-matching returns the most recent constr object TypeVar { + // encapsulate suspension so we can automatically link the suspension of cloned typevars to their original if this turns out to be necessary + def Suspension = new Suspension + class Suspension { + private val suspended = collection.mutable.HashSet[TypeVar]() + def suspend(tv: TypeVar): Unit = { + tv.suspended = true + suspended += tv + } + def resumeAll: Unit = { + for(tv <- suspended) { + tv.suspended = false + } + suspended.clear + } + } + def unapply(tv: TypeVar): Some[(Type, TypeConstraint)] = Some((tv.origin, tv.constr)) def apply(origin: Type, constr: TypeConstraint) = new TypeVar(origin, constr, List(), List()) def apply(tparam: Symbol) = new TypeVar(tparam.tpeHK, new TypeConstraint, List(), tparam.typeParams) // TODO why not initialise TypeConstraint with bounds of tparam? @@ -2226,6 +2259,9 @@ A type's typeSymbol should never be inspected directly. constr.addHiBound(tp, numBound) } + // ignore subtyping&equality checks while true -- see findMember + private[TypeVar] var suspended = false + /** Called from isSubtype0 when a TypeVar is involved in a subtyping check. * if isLowerBound is true, * registerBound returns whether this TypeVar could plausibly be a supertype of tp and, @@ -2258,7 +2294,8 @@ A type's typeSymbol should never be inspected directly. if(isLowerBound) isSubArgs(args1, args2, params) else isSubArgs(args2, args1, params) - if (constr.instValid) // type var is already set + if (suspended) checkSubtype(tp, origin) + else if (constr.instValid) // type var is already set checkSubtype(tp, constr.inst) else isRelatable(tp) && { if(params.isEmpty) { // type var has kind * @@ -2283,7 +2320,8 @@ A type's typeSymbol should never be inspected directly. if(typeVarLHS) constr.inst =:= tp else tp =:= constr.inst - if (constr.instValid) checkIsSameType(tp) + if (suspended) tp =:= origin + else if (constr.instValid) checkIsSameType(tp) else isRelatable(tp) && { undoLog record this @@ -2295,6 +2333,20 @@ A type's typeSymbol should never be inspected directly. } } + /** + * ?A.T =:= tp is rewritten as the constraint ?A <: {type T = tp} + * + * TODO: make these constraints count (incorporate them into implicit search in applyImplicitArgs) + * (T corresponds to @param sym) + */ + def registerTypeSelection(sym: Symbol, tp: Type): Boolean = { + val bound = refinedType(List(WildcardType), NoSymbol) + val bsym = bound.typeSymbol.newAliasType(NoPosition, sym.name) + bsym setInfo tp + bound.decls enter bsym + registerBound(bound, false) + } + /** Can this variable be related in a constraint to type `tp'? * This is not the case if `tp' contains type skolems whose * skolemization level is higher than the level of this variable. @@ -2332,7 +2384,10 @@ A type's typeSymbol should never be inspected directly. override def isVolatile = origin.isVolatile override def kind = "TypeVar" - def cloneInternal = TypeVar(origin, constr cloneInternal, typeArgs, params) // @M TODO: clone args/params? + def cloneInternal = { + assert(!suspended) // cloning a suspended type variable when it's suspended will cause the clone to never be resumed with the current implementation + TypeVar(origin, constr cloneInternal, typeArgs, params) // @M TODO: clone args/params? + } } /** A type carrying some annotations. Created by the typechecker @@ -2505,9 +2560,17 @@ A type's typeSymbol should never be inspected directly. * todo: see how we can clean this up a bit */ def typeRef(pre: Type, sym: Symbol, args: List[Type]): Type = { - var sym1 = if (sym.isAbstractType) rebind(pre, sym) else sym + def rebindTR(pre: Type, sym: Symbol): Symbol = { + if(sym.isAbstractType) rebind(pre, sym) else sym + // type alias selections are rebound in TypeMap ("coevolved", actually -- see #3731) + // e.g., when type parameters that are referenced by the alias are instantiated in the prefix + // see pos/depmet_rebind_typealias + } + val sym1 = rebindTR(pre, sym) + def transform(tp: Type): Type = tp.resultType.asSeenFrom(pre, sym1.owner).instantiateTypeParams(sym1.typeParams, args) + if (sym1.isAliasType && sym1.info.typeParams.length == args.length) { if (!sym1.lockOK) throw new TypeError("illegal cyclic reference involving " + sym1) @@ -2524,8 +2587,7 @@ A type's typeSymbol should never be inspected directly. } else { val pre1 = removeSuper(pre, sym1) if (pre1 ne pre) { - if (sym1.isAbstractType) sym1 = rebind(pre1, sym1) - typeRef(pre1, sym1, args) + typeRef(pre1, rebindTR(pre1, sym1), args) } else if (sym1.isClass && pre.isInstanceOf[CompoundType]) { // sharpen prefix so that it is maximal and still contains the class. @@ -2833,6 +2895,28 @@ A type's typeSymbol should never be inspected directly. case _ => false } + // #3731: return sym1 for which holds: pre bound sym.name to sym and pre1 now binds sym.name to sym1, conceptually exactly the same symbol as sym + // the selection of sym on pre must be updated to the selection of sym1 on pre1, + // since sym's info was probably updated by the TypeMap to yield a new symbol sym1 with transformed info + // @returns sym1 + protected def coevolveSym(pre: Type, pre1: Type, sym: Symbol): Symbol = + if((pre ne pre1) && sym.isAliasType) // only need to rebind type aliases here, as typeRef already handles abstract types (they are allowed to be rebound more liberally) + (pre, pre1) match { + case (RefinedType(_, decls), RefinedType(_, decls1)) => // don't look at parents -- it would be an error to override alias types anyway + //val sym1 = + decls1.lookup(sym.name) +// assert(decls.lookupAll(sym.name).toList.length == 1) +// assert(decls1.lookupAll(sym.name).toList.length == 1) +// assert(sym1.isAliasType) +// println("coevolved "+ sym +" : "+ sym.info +" to "+ sym1 +" : "+ sym1.info +" with "+ pre +" -> "+ pre1) +// sym1 + case _ => // TODO: is there another way a typeref's symbol can refer to a symbol defined in its pre? +// val sym1 = pre1.nonPrivateMember(sym.name).suchThat(sym => sym.isAliasType) +// println("??coevolve "+ sym +" : "+ sym.info +" to "+ sym1 +" : "+ sym1.info +" with "+ pre +" -> "+ pre1) + sym + } + else sym + /** Map this function over given type */ def mapOver(tp: Type): Type = tp match { case TypeRef(pre, sym, args) => @@ -2845,7 +2929,7 @@ A type's typeSymbol should never be inspected directly. else mapOverArgs(args, tparams) } if ((pre1 eq pre) && (args1 eq args)) tp - else typeRef(pre1, sym, args1) + else typeRef(pre1, coevolveSym(pre, pre1, sym), args1) case ThisType(_) => tp case SingleType(pre, sym) => if (sym.isPackageClass) tp // short path @@ -3232,6 +3316,7 @@ A type's typeSymbol should never be inspected directly. /** A base class to compute all substitutions */ abstract class SubstMap[T](from: List[Symbol], to: List[T]) extends TypeMap { + assert(from.length == to.length, "Unsound substitution from "+ from +" to "+ to) /** Are `sym' and `sym1' the same. * Can be tuned by subclasses. @@ -4086,9 +4171,14 @@ A type's typeSymbol should never be inspected directly. case tr1: TypeRef => tp2 match { case tr2: TypeRef => - return equalSymsAndPrefixes(tr1.sym, tr1.pre, tr2.sym, tr2.pre) && + return (equalSymsAndPrefixes(tr1.sym, tr1.pre, tr2.sym, tr2.pre) && ((tp1.isHigherKinded && tp2.isHigherKinded && tp1.normalize =:= tp2.normalize) || - isSameTypes(tr1.args, tr2.args)) + isSameTypes(tr1.args, tr2.args))) || + ((tr1.pre, tr2.pre) match { + case (tv @ TypeVar(_,_), _) => tv.registerTypeSelection(tr1.sym, tr2) + case (_, tv @ TypeVar(_,_)) => tv.registerTypeSelection(tr2.sym, tr1) + case _ => false + }) case _ => } case tt1: ThisType => @@ -4312,7 +4402,7 @@ A type's typeSymbol should never be inspected directly. res1 <:< res2.substSym(tparams2, tparams1) } else { // normalized higher-kinded type //@M for an example of why we need to generate fresh symbols, see neg/tcpoly_ticket2101.scala - val tpsFresh = cloneSymbols(tparams1) // @M cloneSymbols(tparams2) should be equivalent -- TODO: check + val tpsFresh = cloneSymbols(tparams1) (tparams1 corresponds tparams2)((p1, p2) => p2.info.substSym(tparams2, tpsFresh) <:< p1.info.substSym(tparams1, tpsFresh)) && // @PP: corresponds diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala index adcae7d9b1..392223e1e2 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala @@ -234,11 +234,14 @@ self: Analyzer => private def tparamsToWildcards(tp: Type, tparams: List[Symbol]) = tp.instantiateTypeParams(tparams, tparams map (t => WildcardType)) - /* Map a polytype to one in which all type parameters are replaced by wildcards. + /* Map a polytype to one in which all type parameters and argument-dependent types are replaced by wildcards. + * Consider `implicit def b(implicit x: A): x.T = error("")`. We need to approximate DebruijnIndex types + * when checking whether `b` is a valid implicit, as we haven't even searched a value for the implicit arg `x`, + * so we have to approximate (otherwise it is excluded a priori). */ private def depoly(tp: Type): Type = tp match { - case PolyType(tparams, restpe) => tparamsToWildcards(restpe, tparams) - case _ => tp + case PolyType(tparams, restpe) => tparamsToWildcards(ApproximateDependentMap(restpe), tparams) + case _ => ApproximateDependentMap(tp) } /** Does type `dtor` dominate type `dted`? diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index 687f7cae4b..dff9c3d0c3 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -171,9 +171,10 @@ trait Infer { * This method seems to be performance critical. */ def normalize(tp: Type): Type = tp match { - case mt @ MethodType(params, restpe) if (!restpe.isDependent) => - if (mt.isImplicit) normalize(restpe) - else functionType(params map (_.tpe), normalize(restpe)) + case mt @ MethodType(params, restpe) if mt.isImplicit => + normalize(restpe) + case mt @ MethodType(params, restpe) if !restpe.isDependent => + functionType(params map (_.tpe), normalize(restpe)) case PolyType(List(), restpe) => // nullary method type normalize(restpe) case ExistentialType(tparams, qtpe) => @@ -1073,20 +1074,31 @@ trait Infer { substExpr(tree, undetparams, targs, lenientPt) } - /** Substitute free type variables `undetparams; of polymorphic expression - * <code>tree</code>, given prototype <code>pt</code>. - * - * @param tree ... - * @param undetparams ... - * @param pt ... + /** Infer type arguments for `tparams` of polymorphic expression in `tree`, given prototype `pt`. */ def inferExprInstance(tree: Tree, tparams: List[Symbol], pt: Type, keepNothings: Boolean): List[Symbol] = { if (inferInfo) println("infer expr instance "+tree+":"+tree.tpe+"\n"+ " tparams = "+tparams+"\n"+ " pt = "+pt) - val targs = exprTypeArgs(tparams, tree.tpe, pt) + substAdjustedArgs(tree, tparams, pt, exprTypeArgs(tparams, tree.tpe, pt), keepNothings) + } + + /** Infer type arguments for `tparams` of polymorphic expression in `tree`, given prototype `pt`. + * Use specified type `treeTp` instead of `tree.tp` + */ + def inferExprInstance(tree: Tree, tparams: List[Symbol], pt: Type, treeTp: Type, keepNothings: Boolean): List[Symbol] = { + if (inferInfo) + println("infer expr instance "+tree+":"+tree.tpe+"\n"+ + " tparams = "+tparams+"\n"+ + " pt = "+pt) + substAdjustedArgs(tree, tparams, pt, exprTypeArgs(tparams, treeTp, pt), keepNothings) + } + /** Substitute tparams to targs, after adjustment by adjustTypeArgs, + * return tparams that were not determined + */ + def substAdjustedArgs(tree: Tree, tparams: List[Symbol], pt: Type, targs: List[Type], keepNothings: Boolean): List[Symbol] = { if (keepNothings || (targs eq null)) { //@M: adjustTypeArgs fails if targs==null, neg/t0226 substExpr(tree, tparams, targs, pt) List() diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index e71ad5475c..f793da0c54 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -178,18 +178,12 @@ trait Typers { self: Analyzer => */ def applyImplicitArgs(fun: Tree): Tree = fun.tpe match { case MethodType(params, _) => - var positional = true val argResultsBuff = new ListBuffer[SearchResult]() + val argBuff = new ListBuffer[Tree]() - // apply the substitutions (undet type param -> type) that were determined - // by implicit resolution of implicit arguments on the left of this argument - for(param <- params) { - var paramTp = param.tpe - for(ar <- argResultsBuff) - paramTp = paramTp.subst(ar.subst.from, ar.subst.to) - - argResultsBuff += inferImplicit(fun, paramTp, true, false, context) - } + def mkPositionalArg(argTree: Tree, paramName: Name) = argTree + def mkNamedArg(argTree: Tree, paramName: Name) = atPos(argTree.pos)(new AssignOrNamedArg(Ident(paramName), (argTree))) + var mkArg: (Tree, Name) => Tree = mkPositionalArg def errorMessage(paramName: Name, paramTp: Type) = paramTp.typeSymbol match { @@ -200,23 +194,40 @@ trait Typers { self: Analyzer => else "parameter "+paramName+": ")+paramTp } - val argResults = argResultsBuff.toList - val args = argResults.zip(params) flatMap { - case (arg, param) => - if (arg != SearchFailure) { - if (positional) List(arg.tree) - else List(atPos(arg.tree.pos)(new AssignOrNamedArg(Ident(param.name), (arg.tree)))) - } else { - if (!param.hasFlag(DEFAULTPARAM)) - context.error(fun.pos, errorMessage(param.name, param.tpe)) - positional = false - Nil - } + // DEPMETTODO: instantiate type vars that depend on earlier implicit args (see adapt (4.1)) + // + // apply the substitutions (undet type param -> type) that were determined + // by implicit resolution of implicit arguments on the left of this argument + for(param <- params) { + var paramTp = param.tpe + for(ar <- argResultsBuff) + paramTp = paramTp.subst(ar.subst.from, ar.subst.to) + + val res = inferImplicit(fun, paramTp, true, false, context) + argResultsBuff += res + + if (res != SearchFailure) { + argBuff += mkArg(res.tree, param.name) + } else { + mkArg = mkNamedArg // don't pass the default argument (if any) here, but start emitting named arguments for the following args + if (!param.hasFlag(DEFAULTPARAM)) + context.error(fun.pos, errorMessage(param.name, param.tpe)) + /* else { + TODO: alternative (to expose implicit search failure more) --> + resolve argument, do type inference, keep emitting positional args, infer type params based on default value for arg + for (ar <- argResultsBuff) ar.subst traverse defaultVal + val targs = exprTypeArgs(context.undetparams, defaultVal.tpe, paramTp) + substExpr(tree, tparams, targs, pt) + }*/ + } } - for (s <- argResults map (_.subst)) { - s traverse fun - for (arg <- args) s traverse arg + + val args = argBuff.toList + for (ar <- argResultsBuff) { + ar.subst traverse fun + for (arg <- args) ar.subst traverse arg } + new ApplyToImplicitArgs(fun, args) setPos fun.pos case ErrorType => fun @@ -819,10 +830,20 @@ trait Typers { self: Analyzer => context.undetparams = context.undetparams ::: tparams1 adapt(tree1 setType restpe.substSym(tparams, tparams1), mode, pt, original) case mt: MethodType if mt.isImplicit && ((mode & (EXPRmode | FUNmode | LHSmode)) == EXPRmode) => // (4.1) - if (context.undetparams nonEmpty) // (9) -- should revisit dropped condition `(mode & POLYmode) == 0` - // dropped so that type args of implicit method are inferred even if polymorphic expressions are allowed - // needed for implicits in 2.8 collection library -- maybe once #3346 is fixed, we can reinstate the condition? - context.undetparams = inferExprInstance(tree, context.extractUndetparams(), pt, false) // false: retract Nothing's that indicate failure, ambiguities in manifests are dealt with in manifestOfType + if (context.undetparams nonEmpty) { // (9) -- should revisit dropped condition `(mode & POLYmode) == 0` + // dropped so that type args of implicit method are inferred even if polymorphic expressions are allowed + // needed for implicits in 2.8 collection library -- maybe once #3346 is fixed, we can reinstate the condition? + context.undetparams = + inferExprInstance(tree, context.extractUndetparams(), pt, + // approximate types that depend on arguments since dependency on implicit argument is like dependency on type parameter + if(settings.YdepMethTpes.value) mt.approximate else mt, + // if we are looking for a manifest, instantiate type to Nothing anyway, + // as we would get ambiguity errors otherwise. Example + // Looking for a manifest of Nil: This mas many potential types, + // so we need to instantiate to minimal type List[Nothing]. + false) // false: retract Nothing's that indicate failure, ambiguities in manifests are dealt with in manifestOfType + } + val typer1 = constrTyperIf(treeInfo.isSelfOrSuperConstrCall(tree)) if (original != EmptyTree && pt != WildcardType) typer1.silent(tpr => tpr.typed(tpr.applyImplicitArgs(tree), mode, pt)) match { |