From 45768651dd9a1dcbd5ee320d14dcf3523d6a7ed2 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 10 May 2017 22:41:39 +0200 Subject: [PATCH 1/5] Better diagnostic for "failure to disambiguate" errors --- compiler/src/dotty/tools/dotc/core/Denotations.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/core/Denotations.scala b/compiler/src/dotty/tools/dotc/core/Denotations.scala index aea68c34929c..8c356ab0efdf 100644 --- a/compiler/src/dotty/tools/dotc/core/Denotations.scala +++ b/compiler/src/dotty/tools/dotc/core/Denotations.scala @@ -553,7 +553,7 @@ object Denotations { if (sd1.exists) if (sd2.exists) if (isDoubleDef(denot1.symbol, denot2.symbol)) doubleDefError(denot1, denot2) - else throw new TypeError(s"failure to disambiguate overloaded reference $this") + else throw new TypeError(i"failure to disambiguate overloaded reference at $this") else sd1 else sd2 } From 6f9d50c0be190be8d006e5eab517e813a0d4ae95 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 10 May 2017 22:49:19 +0200 Subject: [PATCH 2/5] Prefer method over poly when merging denotations --- .../dotty/tools/dotc/core/Denotations.scala | 26 ++++++++++++++----- 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Denotations.scala b/compiler/src/dotty/tools/dotc/core/Denotations.scala index 8c356ab0efdf..bf88d29d4b37 100644 --- a/compiler/src/dotty/tools/dotc/core/Denotations.scala +++ b/compiler/src/dotty/tools/dotc/core/Denotations.scala @@ -310,12 +310,26 @@ object Denotations { } case tp1: MethodOrPoly => tp2 match { - case tp2: MethodOrPoly - if ctx.typeComparer.matchingParams(tp1, tp2) && - tp1.isImplicit == tp2.isImplicit => - tp1.derivedLambdaType( - mergeParamNames(tp1, tp2), tp1.paramInfos, - infoMeet(tp1.resultType, tp2.resultType.subst(tp2, tp1))) + case tp2: MethodOrPoly => + // Two remedial strategies + // 1. Prefer method types over poly types. This is necessary to handle + // overloaded definitions like the following + // + // def ++ [B >: A](xs: C[B]): D[B] + // def ++ (xs: C[A]): D[A] + // + // (Code like this is found in the collection strawman) + // 2. In the case of two method types or two polytypes with matching + // parameters and implicit status, merge corresppnding parameter + // and result types. + if (tp1.isInstanceOf[PolyType] && tp2.isInstanceOf[MethodType]) tp2 + else if (tp2.isInstanceOf[PolyType] && tp1.isInstanceOf[MethodType]) tp1 + else if (ctx.typeComparer.matchingParams(tp1, tp2) && + tp1.isImplicit == tp2.isImplicit) + tp1.derivedLambdaType( + mergeParamNames(tp1, tp2), tp1.paramInfos, + infoMeet(tp1.resultType, tp2.resultType.subst(tp2, tp1))) + else mergeConflict(tp1, tp2) case _ => mergeConflict(tp1, tp2) } From e2fde1107aa69b387bd297be5973bcd820514ae1 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 10 May 2017 21:27:39 +0200 Subject: [PATCH 3/5] Avoid "value of type does not take parameters" errors --- compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala | 6 ++++++ compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala b/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala index 11472e0e3dff..dcaf1256fbed 100644 --- a/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala +++ b/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala @@ -96,6 +96,12 @@ object ErrorReporting { def exprStr(tree: Tree): String = refStr(tree.tpe) + def takesNoParamsStr(tree: Tree, kind: String) = + if (tree.tpe.widen.exists) + i"${exprStr(tree)} does not take ${kind}parameters" + else + i"undefined: $tree # ${tree.uniqueId}: ${tree.tpe.toString}" + def patternConstrStr(tree: Tree): String = ??? def typeMismatch(tree: Tree, pt: Type, implicitFailure: SearchFailure = NoImplicitMatches): Tree = diff --git a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala index 970b70be5679..93bd2528c380 100644 --- a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala +++ b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala @@ -340,7 +340,7 @@ trait TypeAssigner { else errorType(i"wrong number of arguments for $fntpe: ${fn.tpe}, expected: ${fntpe.paramInfos.length}, found: ${args.length}", tree.pos) case t => - errorType(i"${err.exprStr(fn)} does not take parameters", tree.pos) + errorType(err.takesNoParamsStr(fn, ""), tree.pos) } tree.withType(ownType) } @@ -396,7 +396,7 @@ trait TypeAssigner { else wrongNumberOfTypeArgs(fn.tpe, pt.typeParams, args, tree.pos) } case _ => - errorType(i"${err.exprStr(fn)} does not take type parameters", tree.pos) + errorType(err.takesNoParamsStr(fn, "type "), tree.pos) } tree.withType(ownType) From 7a1f1875260682682fe3a1f3597c5e1fc67258c8 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 10 May 2017 22:22:51 +0200 Subject: [PATCH 4/5] Fix TermRefWithSignature#newLikeThis The signature might need to be updated if the symbol has a different type as seen from the new prefix. --- compiler/src/dotty/tools/dotc/core/Signature.scala | 7 +++++++ compiler/src/dotty/tools/dotc/core/Types.scala | 11 +++++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Signature.scala b/compiler/src/dotty/tools/dotc/core/Signature.scala index fcd1e23767df..8392024abfbc 100644 --- a/compiler/src/dotty/tools/dotc/core/Signature.scala +++ b/compiler/src/dotty/tools/dotc/core/Signature.scala @@ -49,6 +49,13 @@ case class Signature(paramsSig: List[TypeName], resSig: TypeName) { loop(this.paramsSig, that.paramsSig) } + /** Is this siganture consistent with that signature? + * This is the case if the signatures have consistent parameters + * and result types. + */ + final def consistentWith(that: Signature): Boolean = + consistentParams(that) && consistent(resSig, that.resSig) + /** The degree to which this signature matches `that`. * If parameter names are consistent and result types names match (i.e. they are the same * or one is a wildcard), the result is `FullMatch`. diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 9a25da62be1c..7abaec7341c4 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -1867,8 +1867,15 @@ object Types { } else candidate - override def newLikeThis(prefix: Type)(implicit ctx: Context): TermRef = - fixDenot(TermRef.withSig(prefix, name, sig), prefix) + override def newLikeThis(prefix: Type)(implicit ctx: Context): TermRef = { + // If symbol exists, the new signature is the symbol's signature as seen + // from the new prefix, modulo consistency + val symSig = + if (symbol.exists) symbol.info.asSeenFrom(prefix, symbol.owner).signature + else sig + val newSig = if (sig.consistentWith(symSig)) sig else symSig + fixDenot(TermRef.withSig(prefix, name, newSig), prefix) + } override def shadowed(implicit ctx: Context): NamedType = fixDenot(TermRef.withSig(prefix, name.derived(ShadowedName), sig), prefix) From 44d6d3788181d96b6daa7712104ae9d4c900c67b Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 11 May 2017 10:27:46 +0200 Subject: [PATCH 5/5] Tweak signature update Need to keep all consistent parts of original signature. --- .../dotty/tools/dotc/core/Denotations.scala | 4 +++- .../src/dotty/tools/dotc/core/Signature.scala | 21 ++++++++++++------- .../src/dotty/tools/dotc/core/Types.scala | 11 ++++++---- 3 files changed, 24 insertions(+), 12 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Denotations.scala b/compiler/src/dotty/tools/dotc/core/Denotations.scala index bf88d29d4b37..c0bad8ded708 100644 --- a/compiler/src/dotty/tools/dotc/core/Denotations.scala +++ b/compiler/src/dotty/tools/dotc/core/Denotations.scala @@ -311,7 +311,8 @@ object Denotations { case tp1: MethodOrPoly => tp2 match { case tp2: MethodOrPoly => - // Two remedial strategies + // Two remedial strategies: + // // 1. Prefer method types over poly types. This is necessary to handle // overloaded definitions like the following // @@ -319,6 +320,7 @@ object Denotations { // def ++ (xs: C[A]): D[A] // // (Code like this is found in the collection strawman) + // // 2. In the case of two method types or two polytypes with matching // parameters and implicit status, merge corresppnding parameter // and result types. diff --git a/compiler/src/dotty/tools/dotc/core/Signature.scala b/compiler/src/dotty/tools/dotc/core/Signature.scala index 8392024abfbc..f310eefeb851 100644 --- a/compiler/src/dotty/tools/dotc/core/Signature.scala +++ b/compiler/src/dotty/tools/dotc/core/Signature.scala @@ -1,7 +1,7 @@ package dotty.tools.dotc package core -import Names._, Types._, Contexts._, StdNames._ +import Names._, Types._, Contexts._, StdNames._, Decorators._ import TypeErasure.sigName import scala.annotation.tailrec @@ -49,12 +49,19 @@ case class Signature(paramsSig: List[TypeName], resSig: TypeName) { loop(this.paramsSig, that.paramsSig) } - /** Is this siganture consistent with that signature? - * This is the case if the signatures have consistent parameters - * and result types. - */ - final def consistentWith(that: Signature): Boolean = - consistentParams(that) && consistent(resSig, that.resSig) + /** `that` signature, but keeping all corresponding parts of `this` signature. */ + final def updateWith(that: Signature): Signature = { + def update(name1: TypeName, name2: TypeName): TypeName = + if (consistent(name1, name2)) name1 else name2 + if (this == that) this + else if (!this.paramsSig.hasSameLengthAs(that.paramsSig)) that + else { + val mapped = Signature( + this.paramsSig.zipWithConserve(that.paramsSig)(update), + update(this.resSig, that.resSig)) + if (mapped == this) this else mapped + } + } /** The degree to which this signature matches `that`. * If parameter names are consistent and result types names match (i.e. they are the same diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 7abaec7341c4..ac3245c37db3 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -1870,10 +1870,13 @@ object Types { override def newLikeThis(prefix: Type)(implicit ctx: Context): TermRef = { // If symbol exists, the new signature is the symbol's signature as seen // from the new prefix, modulo consistency - val symSig = - if (symbol.exists) symbol.info.asSeenFrom(prefix, symbol.owner).signature - else sig - val newSig = if (sig.consistentWith(symSig)) sig else symSig + val newSig = + if (sig == Signature.NotAMethod || !symbol.exists) + sig + else + sig.updateWith(symbol.info.asSeenFrom(prefix, symbol.owner).signature) + if (newSig ne sig) + core.println(i"sig change at ${ctx.phase} for $this, pre = $prefix, sig: $sig --> $newSig") fixDenot(TermRef.withSig(prefix, name, newSig), prefix) }