summaryrefslogtreecommitdiff
path: root/src/compiler
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2012-03-21 12:33:57 -0700
committerPaul Phillips <paulp@improving.org>2012-03-21 12:33:57 -0700
commita36a05933499acd3aeeb414d36099ea8ae6e6ca9 (patch)
treefda17e3d9b62a0ba70683ca1782a20d90630c840 /src/compiler
parentbd8bff3370a124330ee51747826dba855497487c (diff)
parent5d555ef90f443e20d2e46c668e456df0a643dae8 (diff)
downloadscala-a36a05933499acd3aeeb414d36099ea8ae6e6ca9.tar.gz
scala-a36a05933499acd3aeeb414d36099ea8ae6e6ca9.tar.bz2
scala-a36a05933499acd3aeeb414d36099ea8ae6e6ca9.zip
Merge branch 'issue/SI-5580' of /scala/trunk into develop
Diffstat (limited to 'src/compiler')
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala54
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Namers.scala4
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala48
3 files changed, 86 insertions, 20 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala b/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala
index f32ad9293c..5287fad3bb 100644
--- a/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/MethodSynthesis.scala
@@ -169,6 +169,16 @@ trait MethodSynthesis {
self: Namer =>
import NamerErrorGen._
+
+ /** TODO - synthesize method.
+ */
+ def enterImplicitClass(tree: ClassDef) {
+ /** e.g.
+ val ClassDef(mods, name, tparams, impl) = tree
+ val converter = ImplicitClassConverter(tree).createAndEnterSymbol()
+ ...
+ */
+ }
def enterGetterSetter(tree: ValDef) {
val ValDef(mods, name, _, _) = tree
@@ -230,14 +240,33 @@ trait MethodSynthesis {
}
trait Derived {
+ /** The tree from which we are deriving a synthetic member. */
+ def tree: Tree
def name: TermName
def flagsMask: Long
def flagsExtra: Long
+
+ /** The tree, symbol, and type completer for the synthetic member. */
def completer(sym: Symbol): Type
+ def derivedSym: Symbol
+ def derivedTree: Tree
}
- trait DerivedFromValDef extends Derived {
- /** The declaration from which we are deriving.
- */
+
+ trait DerivedFromMemberDef extends Derived {
+ def tree: MemberDef
+
+ // Final methods to make the rest easier to reason about.
+ final def mods = tree.mods
+ final def basisSym = tree.symbol
+ final def enclClass = basisSym.enclClass
+ final def derivedFlags: Long = basisSym.flags & flagsMask | flagsExtra
+ }
+
+ trait DerivedFromClassDef extends DerivedFromMemberDef {
+ def tree: ClassDef
+ }
+
+ trait DerivedFromValDef extends DerivedFromMemberDef {
def tree: ValDef
/** Which meta-annotation is associated with this kind of entity.
@@ -245,14 +274,8 @@ trait MethodSynthesis {
*/
def category: Symbol
- // Final methods to make the rest easier to reason about.
- final def mods = tree.mods
- final def basisSym = tree.symbol
- final def enclClass = basisSym.enclClass
-
final def completer(sym: Symbol) = namerOf(sym).accessorTypeCompleter(tree, isSetter)
final def fieldSelection = Select(This(enclClass), basisSym)
- final def derivedFlags: Long = basisSym.flags & flagsMask | flagsExtra
final def derivedMods: Modifiers = mods & flagsMask | flagsExtra mapAnnotations (_ => Nil)
def derivedSym: Symbol = tree.symbol
@@ -312,6 +335,19 @@ trait MethodSynthesis {
private def setterDef = DefDef(derivedSym, setterRhs)
override def derivedTree: Tree = if (setterParam == NoSymbol) EmptyTree else setterDef
}
+
+ /** A synthetic method which performs the implicit conversion implied by
+ * the declaration of an implicit class. Yet to be written.
+ */
+ case class ImplicitClassConverter(tree: ClassDef) extends DerivedFromClassDef {
+ def completer(sym: Symbol): Type = ???
+ def derivedSym: Symbol = ???
+ def derivedTree: DefDef = ???
+ def flagsExtra: Long = ???
+ def flagsMask: Long = ???
+ def name: TermName = ???
+ }
+
case class Getter(tree: ValDef) extends DerivedGetter {
def name = tree.name
def category = GetterTargetClass
diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
index c5fb13a5a9..6b27c27652 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
@@ -665,6 +665,10 @@ trait Namers extends MethodSynthesis {
"If possible, define " + tree.symbol + " in " + owner.skipPackageObject + " instead."
)
}
+
+ // Suggested location only.
+ if (mods.isImplicit)
+ enterImplicitClass(tree)
}
// this logic is needed in case typer was interrupted half
diff --git a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala
index e17a271dd0..6efa595d99 100644
--- a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala
@@ -252,12 +252,17 @@ trait TypeDiagnostics {
}
"" // no elaborable variance situation found
}
- def foundReqMsg(found: Type, req: Type): String = (
- withDisambiguation(Nil, found, req)(
+ // TODO - figure out how to avoid doing any work at all
+ // when the message will never be seen. I though context.reportErrors
+ // being false would do that, but if I return "<suppressed>" under
+ // that condition, I see it.
+ def foundReqMsg(found: Type, req: Type): String = {
+ def baseMessage = (
";\n found : " + found.toLongString + existentialContext(found) + explainAlias(found) +
"\n required: " + req + existentialContext(req) + explainAlias(req)
- ) + explainVariance(found, req)
- )
+ )
+ withDisambiguation(Nil, found, req)(baseMessage) + explainVariance(found, req)
+ }
case class TypeDiag(tp: Type, sym: Symbol) extends Ordered[TypeDiag] {
// save the name because it will be mutated until it has been
@@ -307,16 +312,37 @@ trait TypeDiagnostics {
)
}
}
- private def typeDiags(locals: List[Symbol], types: Type*): List[TypeDiag] = {
- object SymExtractor {
- def unapply(x: Any) = x match {
- case t @ ConstantType(_) => Some(t -> t.underlying.typeSymbol)
- case t @ TypeRef(_, sym, _) => if (locals contains sym) None else Some(t -> sym)
- case _ => None
+ /** This is tricky stuff - we need to traverse types deeply to
+ * explain name ambiguities, which may occur anywhere. However
+ * when lub explosions come through it knocks us into an n^2
+ * disaster, see SI-5580. This is trying to perform the initial
+ * filtering of possibly ambiguous types in a sufficiently
+ * aggressive way that the state space won't explode.
+ */
+ private def typeDiags(locals: List[Symbol], types0: Type*): List[TypeDiag] = {
+ val types = types0.toList
+ // If two different type diag instances are seen for a given
+ // key (either the string representation of a type, or the simple
+ // name of a symbol) then keep them for disambiguation.
+ val strings = mutable.Map[String, Set[TypeDiag]]() withDefaultValue Set()
+ val names = mutable.Map[Name, Set[TypeDiag]]() withDefaultValue Set()
+
+ def record(t: Type, sym: Symbol) = {
+ val diag = TypeDiag(t, sym)
+
+ strings("" + t) += diag
+ names(sym.name) += diag
+ }
+ for (tpe <- types ; t <- tpe) {
+ t match {
+ case ConstantType(_) => record(t, t.underlying.typeSymbol)
+ case TypeRef(_, sym, _) => record(t, sym)
+ case _ => ()
}
}
- for (tp <- types.toList; SymExtractor(t, sym) <- tp) yield TypeDiag(t, sym)
+ val collisions = strings.values ++ names.values filter (_.size > 1)
+ collisions.flatten.toList
}
/** The distinct pairs from an ordered list. */