diff options
Diffstat (limited to 'src/compiler/scala/tools/nsc/doc/model/ModelFactoryImplicitSupport.scala')
-rw-r--r-- | src/compiler/scala/tools/nsc/doc/model/ModelFactoryImplicitSupport.scala | 134 |
1 files changed, 23 insertions, 111 deletions
diff --git a/src/compiler/scala/tools/nsc/doc/model/ModelFactoryImplicitSupport.scala b/src/compiler/scala/tools/nsc/doc/model/ModelFactoryImplicitSupport.scala index 64205104aa..c3525037cd 100644 --- a/src/compiler/scala/tools/nsc/doc/model/ModelFactoryImplicitSupport.scala +++ b/src/compiler/scala/tools/nsc/doc/model/ModelFactoryImplicitSupport.scala @@ -63,8 +63,8 @@ trait ModelFactoryImplicitSupport { // debugging: val DEBUG: Boolean = settings.docImplicitsDebug.value val ERROR: Boolean = true // currently we show all errors - @inline final def debug(msg: => String) = if (DEBUG) settings.printMsg(msg) - @inline final def error(msg: => String) = if (ERROR) settings.printMsg(msg) + @inline final def debug(msg: => String) = if (DEBUG) println(msg) + @inline final def error(msg: => String) = if (ERROR) println(msg) /** This is a flag that indicates whether to eliminate implicits that cannot be satisfied within the current scope. * For example, if an implicit conversion requires that there is a Numeric[T] in scope: @@ -96,17 +96,6 @@ trait ModelFactoryImplicitSupport { def targetType: TypeEntity = makeType(toType, inTpl) - def targetTemplate: Option[TemplateEntity] = toType match { - // @Vlad: I'm being extra conservative in template creation -- I don't want to create templates for complex types - // such as refinement types because the template can't represent the type corectly (a template corresponds to a - // package, class, trait or object) - case t: TypeRef => Some(makeTemplate(t.sym)) - case RefinedType(parents, decls) => None - case _ => error("Scaladoc implicits: Could not create template for: " + toType + " of type " + toType.getClass); None - } - - def targetTypeComponents: List[(TemplateEntity, TypeEntity)] = makeParentTypes(toType, inTpl) - def convertorOwner: TemplateEntity = if (convSym != NoSymbol) makeTemplate(convSym.owner) @@ -137,15 +126,20 @@ trait ModelFactoryImplicitSupport { lazy val constraints: List[Constraint] = constrs - private val memberImpls: List[MemberImpl] = { + val members: List[MemberEntity] = { // Obtain the members inherited by the implicit conversion - val memberSyms = toType.members.filter(implicitShouldDocument(_)) - val existingSyms = sym.info.members + var memberSyms = toType.members.filter(implicitShouldDocument(_)) + val existingMembers = sym.info.members // Debugging part :) debug(sym.nameString + "\n" + "=" * sym.nameString.length()) debug(" * conversion " + convSym + " from " + sym.tpe + " to " + toType) + // Members inherited by implicit conversions cannot override actual members + memberSyms = memberSyms.filterNot((sym1: Symbol) => + existingMembers.exists(sym2 => sym1.name == sym2.name && + !isDistinguishableFrom(toType.memberInfo(sym1), sym.info.memberInfo(sym2)))) + debug(" -> full type: " + toType) if (constraints.length != 0) { debug(" -> constraints: ") @@ -155,89 +149,10 @@ trait ModelFactoryImplicitSupport { memberSyms foreach (sym => debug(" - "+ sym.decodedName +" : " + sym.info)) debug("") - memberSyms.flatMap({ aSym => - makeTemplate(aSym.owner) match { - case d: DocTemplateImpl => - // we can't just pick up nodes from the previous template, although that would be very convenient: - // they need the byConversion field to be attached to themselves -- this is design decision I should - // revisit soon - // - // d.ownMembers.collect({ - // // it's either a member or has a couple of usecases it's hidden behind - // case m: MemberImpl if m.sym == aSym => - // m // the member itself - // case m: MemberImpl if m.useCaseOf.isDefined && m.useCaseOf.get.asInstanceOf[MemberImpl].sym == aSym => - // m.useCaseOf.get.asInstanceOf[MemberImpl] // the usecase - // }) - makeMember(aSym, new ImplicitConversionInfoImpl(this), d) - case _ => - // should only happen if the code for this template is not part of the scaladoc run => - // members won't have any comments - makeMember(aSym, new ImplicitConversionInfoImpl(this), inTpl) - } - }) - } - - def members: List[MemberEntity] = memberImpls - - def populateShadowingTables(allConvs: List[ImplicitConversionImpl]): Unit = { - - // TODO: This is not clean, we need to put sym.info.members here instead of tpl.memberSyms to avoid - // the localShouldDocument(_) filtering in ModelFactory - val originalClassMembers = inTpl.memberSyms - val otherConversions = allConvs.filterNot(_ == this) - assert(otherConversions.length == allConvs.length - 1) - - for (member <- memberImpls) { - // for each member in our list - val sym1 = member.sym - val tpe1 = toType.memberInfo(sym1) - - // check if it's shadowed by a member in the original class - var shadowedBySyms: List[Symbol] = List() - for (sym2 <- originalClassMembers) - if (sym1.name == sym2.name) { - val shadowed = !settings.docImplicitsSoundShadowing.value || { - val tpe2 = inTpl.sym.info.memberInfo(sym2) - !isDistinguishableFrom(tpe1, tpe2) - } - if (shadowed) - shadowedBySyms ::= sym2 - } - - val shadowedByMembers = inTpl.allOwnMembers.filter((mb: MemberImpl) => shadowedBySyms.contains(mb.sym)) - - // check if it's shadowed by another member - var ambiguousByMembers: List[MemberEntity] = List() - for (conv <- otherConversions) - for (member2 <- conv.memberImpls) { - val sym2 = member2.sym - if (sym1.name == sym2.name) { - val tpe2 = conv.toType.memberInfo(sym2) - // Ambiguity should be an equivalence relation - val ambiguated = !isDistinguishableFrom(tpe1, tpe2) || !isDistinguishableFrom(tpe2, tpe1) - if (ambiguated) - ambiguousByMembers ::= member2 - } - } - - // we finally have the shadowing info - val shadowing = new ImplicitMemberShadowing { - def shadowingMembers: List[MemberEntity] = shadowedByMembers - def ambiguatingMembers: List[MemberEntity] = ambiguousByMembers - } - - member.byConversion.get.asInstanceOf[ImplicitConversionInfoImpl].shadowing = shadowing - } + memberSyms.flatMap((makeMember(_, this, inTpl))) } } - class ImplicitConversionInfoImpl( - val conversion: ImplicitConversionImpl) extends ImplicitConversionInfo { - // this will be updated as a side effect - var shadowing: ImplicitMemberShadowing = null - } - /* ============== MAKER METHODS ============== */ /** @@ -256,22 +171,18 @@ trait ModelFactoryImplicitSupport { val results = global.analyzer.allViewsFrom(sym.tpe, context, sym.typeParams) var conversions = results.flatMap(result => makeImplicitConversion(sym, result._1, result._2, context, inTpl)) - // also keep empty conversions, so they appear in diagrams - // conversions = conversions.filter(!_.members.isEmpty) + conversions = conversions.filterNot(_.members.isEmpty) // Filter out specialized conversions from array if (sym == ArrayClass) - conversions = conversions.filterNot((conv: ImplicitConversionImpl) => + conversions = conversions.filterNot((conv: ImplicitConversion) => hardcoded.arraySkipConversions.contains(conv.conversionQualifiedName)) // Filter out non-sensical conversions from value types if (isPrimitiveValueType(sym.tpe)) - conversions = conversions.filter((ic: ImplicitConversionImpl) => + conversions = conversions.filter((ic: ImplicitConversion) => hardcoded.valueClassFilter(sym.nameString, ic.conversionQualifiedName)) - // side-effecting and ugly shadowing table population -- ugly but effective - conversions.map(_.populateShadowingTables(conversions)) - // Put the class-specific conversions in front val (ownConversions, commonConversions) = conversions.partition(conv => !hardcoded.commonConversionTargets.contains(conv.conversionQualifiedName)) @@ -307,7 +218,7 @@ trait ModelFactoryImplicitSupport { * - we also need to transform implicit parameters in the view's signature into constraints, such that Numeric[T4] * appears as a constraint */ - def makeImplicitConversion(sym: Symbol, result: SearchResult, constrs: List[TypeConstraint], context: Context, inTpl: => DocTemplateImpl): List[ImplicitConversionImpl] = + def makeImplicitConversion(sym: Symbol, result: SearchResult, constrs: List[TypeConstraint], context: Context, inTpl: => DocTemplateImpl): List[ImplicitConversion] = if (result.tree == EmptyTree) Nil else { // `result` will contain the type of the view (= implicit conversion method) @@ -582,8 +493,8 @@ trait ModelFactoryImplicitSupport { // - common methods (in Any, AnyRef, Object) as they are automatically removed // - private and protected members (not accessible following an implicit conversion) // - members starting with _ (usually reserved for internal stuff) - localShouldDocument(aSym) && (!aSym.isConstructor) && (aSym.owner != AnyValClass) && - (aSym.owner != AnyClass) && (aSym.owner != ObjectClass) && + localShouldDocument(aSym) && (!aSym.isConstructor) && (aSym.owner != ObjectClass) && + (aSym.owner != AnyClass) && (aSym.owner != AnyRefClass) && (!aSym.isProtected) && (!aSym.isPrivate) && (!aSym.name.startsWith("_")) && (aSym.isMethod || aSym.isGetter || aSym.isSetter) && (aSym.nameString != "getClass") @@ -598,11 +509,12 @@ trait ModelFactoryImplicitSupport { def isDistinguishableFrom(t1: Type, t2: Type): Boolean = if (t1.paramss.map(_.length) == t2.paramss.map(_.length)) { for ((t1p, t2p) <- t1.paramss.flatten zip t2.paramss.flatten) - if (!isSubType(t1 memberInfo t1p, t2 memberInfo t2p)) - return true // if on the corresponding parameter you give a type that is in t1 but not in t2 - // def foo(a: Either[Int, Double]): Int = 3 - // def foo(b: Left[T1]): Int = 6 - // a.foo(Right(4.5d)) prints out 3 :) + if (!isSubType(t1 memberInfo t1p, t2 memberInfo t2p)) + return true // if on the corresponding parameter you give a type that is in t1 but not in t2 + // example: + // def foo(a: Either[Int, Double]): Int = 3 + // def foo(b: Left[T1]): Int = 6 + // a.foo(Right(4.5d)) prints out 3 :) false } else true // the member structure is different foo(3, 5) vs foo(3)(5) }
\ No newline at end of file |