diff options
author | Paul Phillips <paulp@improving.org> | 2012-03-21 12:33:57 -0700 |
---|---|---|
committer | Paul Phillips <paulp@improving.org> | 2012-03-21 12:33:57 -0700 |
commit | a36a05933499acd3aeeb414d36099ea8ae6e6ca9 (patch) | |
tree | fda17e3d9b62a0ba70683ca1782a20d90630c840 /src/compiler | |
parent | bd8bff3370a124330ee51747826dba855497487c (diff) | |
parent | 5d555ef90f443e20d2e46c668e456df0a643dae8 (diff) | |
download | scala-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')
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. */ |