summaryrefslogtreecommitdiff
path: root/src/compiler
diff options
context:
space:
mode:
authorAdriaan Moors <adriaan.moors@epfl.ch>2010-09-16 22:26:24 +0000
committerAdriaan Moors <adriaan.moors@epfl.ch>2010-09-16 22:26:24 +0000
commite557acb9a7d672c0635c3eaf9fe385adc41e5c86 (patch)
treed13db6639464acc57f0e44b4b3ef6f3e607ad403 /src/compiler
parentce223fe7abc47af712382a64404604e75f9f4d20 (diff)
downloadscala-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')
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Types.scala158
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Implicits.scala9
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Infer.scala32
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala79
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 {