From 749934aeafecc65c865d92056467c08540add8cc Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 22 Aug 2013 14:24:49 +0200 Subject: More typer bug fixes and improvements in error messages --- src/dotty/tools/dotc/ast/Trees.scala | 13 ++++++++----- src/dotty/tools/dotc/ast/TypedTrees.scala | 2 +- src/dotty/tools/dotc/ast/UntypedTrees.scala | 2 +- src/dotty/tools/dotc/core/Symbols.scala | 3 +-- src/dotty/tools/dotc/core/Types.scala | 2 +- src/dotty/tools/dotc/parsing/Parsers.scala | 2 +- src/dotty/tools/dotc/typer/Applications.scala | 6 +++--- src/dotty/tools/dotc/typer/ErrorReporting.scala | 16 ++++++++-------- src/dotty/tools/dotc/typer/Implicits.scala | 3 ++- src/dotty/tools/dotc/typer/Namer.scala | 3 +-- src/dotty/tools/dotc/typer/Typer.scala | 14 ++++++++++---- 11 files changed, 37 insertions(+), 29 deletions(-) (limited to 'src/dotty') diff --git a/src/dotty/tools/dotc/ast/Trees.scala b/src/dotty/tools/dotc/ast/Trees.scala index 8157c287d..254818b27 100644 --- a/src/dotty/tools/dotc/ast/Trees.scala +++ b/src/dotty/tools/dotc/ast/Trees.scala @@ -180,7 +180,13 @@ object Trees { /** Return a typed tree that's isomorphic to this tree, but has given * type. (Overridden by empty trees) */ - def withType(tpe: Type): ThisTree[Type] = { + def withType(tpe: Type)(implicit ctx: Context): ThisTree[Type] = { + // temporary solution to catch unreported errors early + if (tpe == ErrorType) assert(ctx.reporter.hasErrors) + withTypeUnchecked(tpe) + } + + def withTypeUnchecked(tpe: Type): ThisTree[Type] = { val tree = (if (myTpe == null || (myTpe.asInstanceOf[AnyRef] eq tpe.asInstanceOf[AnyRef])) this @@ -650,7 +656,7 @@ object Trees { trait WithoutType[-T >: Untyped] extends Tree[T] { override def tpe: T @uncheckedVariance = NoType.asInstanceOf[T] - override def withType(tpe: Type) = this.asInstanceOf[ThisTree[Type]] + override def withTypeUnchecked(tpe: Type) = this.asInstanceOf[ThisTree[Type]] } /** Temporary class that results from translation of ModuleDefs @@ -816,9 +822,6 @@ object Trees { def finalize(tree: Tree, copied: untpd.Tree): copied.ThisTree[T] = postProcess(tree, copied withPos tree.pos) - private def copyAttrs(t: untpd.Tree, tree: Tree): t.ThisTree[T] = - t.withType(tree.typeOpt).withPos(tree.pos).asInstanceOf[t.ThisTree[T]] - def Ident(tree: Tree, name: Name): Ident = tree match { case tree: BackquotedIdent => if (name == tree.name) tree diff --git a/src/dotty/tools/dotc/ast/TypedTrees.scala b/src/dotty/tools/dotc/ast/TypedTrees.scala index 2200e7fe5..a34e015b8 100644 --- a/src/dotty/tools/dotc/ast/TypedTrees.scala +++ b/src/dotty/tools/dotc/ast/TypedTrees.scala @@ -356,7 +356,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { class TypedTreeCopier extends TreeCopier { def postProcess(tree: Tree, copied: untpd.Tree): copied.ThisTree[Type] = - copied.withType(tree.tpe) + copied.withTypeUnchecked(tree.tpe) } implicit class TreeOps[ThisTree <: tpd.Tree](val tree: ThisTree) extends AnyVal { diff --git a/src/dotty/tools/dotc/ast/UntypedTrees.scala b/src/dotty/tools/dotc/ast/UntypedTrees.scala index b3b05dc8b..d7e0a7b3d 100644 --- a/src/dotty/tools/dotc/ast/UntypedTrees.scala +++ b/src/dotty/tools/dotc/ast/UntypedTrees.scala @@ -110,7 +110,7 @@ object untpd extends Trees.Instance[Untyped] with TreeInfo[Untyped] { def AppliedTypeTree(tpt: Tree, arg: Tree): AppliedTypeTree = AppliedTypeTree(tpt, arg :: Nil) - def TypeTree(tpe: Type): TypedSplice = TypedSplice(TypeTree().withType(tpe)) + def TypeTree(tpe: Type): TypedSplice = TypedSplice(TypeTree().withTypeUnchecked(tpe)) def TypeDef(mods: Modifiers, name: TypeName, tparams: List[TypeDef], rhs: Tree): TypeDef = if (tparams.isEmpty) TypeDef(mods, name, rhs) else new PolyTypeDef(mods, name, tparams, rhs) diff --git a/src/dotty/tools/dotc/core/Symbols.scala b/src/dotty/tools/dotc/core/Symbols.scala index 72dcef082..fe39135d9 100644 --- a/src/dotty/tools/dotc/core/Symbols.scala +++ b/src/dotty/tools/dotc/core/Symbols.scala @@ -368,9 +368,8 @@ object Symbols { * the class containing this symbol was generated, null if not applicable. * Overridden in ClassSymbol */ - def associatedFile(implicit ctx: Context): AbstractFile = ctx.traceIndented(s"assocFile($this)") { + def associatedFile(implicit ctx: Context): AbstractFile = denot.topLevelClass.symbol.associatedFile - } /** The class file from which this class was generated, null if not applicable. */ final def binaryFile(implicit ctx: Context): AbstractFile = diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala index 63ce59995..b9d079a20 100644 --- a/src/dotty/tools/dotc/core/Types.scala +++ b/src/dotty/tools/dotc/core/Types.scala @@ -493,7 +493,7 @@ object Types { } /** The basetype of this type with given class symbol */ - final def baseType(base: Symbol)(implicit ctx: Context): Type = ctx.traceIndented(s"$this baseType $base") { base.denot match { + final def baseType(base: Symbol)(implicit ctx: Context): Type = /*ctx.traceIndented(s"$this baseType $base")*/ { base.denot match { case classd: ClassDenotation => classd.baseTypeOf(this) case _ => NoType }} diff --git a/src/dotty/tools/dotc/parsing/Parsers.scala b/src/dotty/tools/dotc/parsing/Parsers.scala index abba1be37..8f8928f58 100644 --- a/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/src/dotty/tools/dotc/parsing/Parsers.scala @@ -1666,7 +1666,7 @@ object Parsers { } else { equalsExpr() } - DefDef(mods, name, tparams, vparamss, restype, rhs) + DefDef(mods | Method, name, tparams, vparamss, restype, rhs) } } diff --git a/src/dotty/tools/dotc/typer/Applications.scala b/src/dotty/tools/dotc/typer/Applications.scala index 05b0c50ce..8af9e0b57 100644 --- a/src/dotty/tools/dotc/typer/Applications.scala +++ b/src/dotty/tools/dotc/typer/Applications.scala @@ -118,7 +118,8 @@ trait Applications extends Compatibility { self: Typer => case methType: MethodType => // apply the result type constraint, unless method type is dependent if (!methType.isDependent) - ok = ok && constrainResult(methType.resultType, resultType) + if (!constrainResult(methType.resultType, resultType)) + fail(err.typeMismatchStr(methType.resultType, resultType)) // match all arguments with corresponding formal parameters matchArgs(orderedArgs, methType.paramTypes, 0) case _ => @@ -484,7 +485,6 @@ trait Applications extends Compatibility { self: Typer => typed(assign) } - realApply if (untpd.isOpAssign(tree)) tryEither { implicit ctx => realApply @@ -706,7 +706,7 @@ trait Applications extends Compatibility { self: Typer => } private val dummyTree = untpd.Literal(Constant(null)) - def dummyTreeOfType(tp: Type): Tree = dummyTree withType tp + def dummyTreeOfType(tp: Type): Tree = dummyTree withTypeUnchecked tp /** Resolve overloaded alternative `alts`, given expected type `pt`. */ def resolveOverloaded(alts: List[TermRef], pt: Type)(implicit ctx: Context): List[TermRef] = { diff --git a/src/dotty/tools/dotc/typer/ErrorReporting.scala b/src/dotty/tools/dotc/typer/ErrorReporting.scala index d95807e3c..177882688 100644 --- a/src/dotty/tools/dotc/typer/ErrorReporting.scala +++ b/src/dotty/tools/dotc/typer/ErrorReporting.scala @@ -63,16 +63,16 @@ object ErrorReporting { def patternConstrStr(tree: Tree): String = ??? - def typeMismatch(tree: Tree, pt: Type): Tree = { - val result = errorTree(tree, - i"""type mismatch: - | found : ${tree.tpe} - | required: $pt""".stripMargin) + def typeMismatch(tree: Tree, pt: Type): Tree = + errorTree(tree, typeMismatchStr(tree.tpe, pt)) + + def typeMismatchStr(found: Type, expected: Type) = { if (ctx.settings.explaintypes.value) - new ExplainingTypeComparer().isSubType(tree.tpe, pt) - result + new ExplainingTypeComparer().isSubType(found, expected) + i"""type mismatch: + | found : $found + | required: $expected""".stripMargin } - } def err(implicit ctx: Context): Errors = new Errors diff --git a/src/dotty/tools/dotc/typer/Implicits.scala b/src/dotty/tools/dotc/typer/Implicits.scala index b98ea5dc9..74a144996 100644 --- a/src/dotty/tools/dotc/typer/Implicits.scala +++ b/src/dotty/tools/dotc/typer/Implicits.scala @@ -183,7 +183,8 @@ trait Implicits { self: Typer => * @param pos The position where errors should be reported. * @param reportAmbiguous Should ambiguity errors be reported? False when called from `viewExists`. */ - def inferImplicit(pt: Type, argument: Tree, pos: Position, reportAmbiguous: Boolean = true)(implicit ctx: Context): Tree = { + def inferImplicit(pt: Type, argument: Tree, pos: Position, reportAmbiguous: Boolean = true)(implicit ctx: Context): Tree = + ctx.traceIndented(s"search implicit $pt, arg = ${argument.show}, reportAmbiguous = $reportAmbiguous", show = true) { new ImplicitSearch(pt, argument, pos).bestImplicit match { case SearchSuccess(_, tree, tstate) => tstate.commit() diff --git a/src/dotty/tools/dotc/typer/Namer.scala b/src/dotty/tools/dotc/typer/Namer.scala index bedaf55c3..426213147 100644 --- a/src/dotty/tools/dotc/typer/Namer.scala +++ b/src/dotty/tools/dotc/typer/Namer.scala @@ -147,7 +147,6 @@ class Namer { typer: Typer => adjustIfModule(new Completer(tree), tree), privateWithinClass(tree.mods), tree.pos, ctx.source.file)) case tree: MemberDef => - var completer = new Completer(tree) record(tree, ctx.newSymbol( ctx.owner, tree.name, tree.mods.flags, adjustIfModule(new Completer(tree), tree), @@ -385,7 +384,7 @@ class Namer { typer: Typer => else tparams map symbolOfTree def wrapMethType(restpe: Type): Type = { val monotpe = - (restpe /: vparamss) { (restpe, params) => + (vparamss :\ restpe) { (params, restpe) => val make = if (params.nonEmpty && (params.head.mods is Implicit)) ImplicitMethodType else MethodType diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala index 82b2e25b6..c693209f4 100644 --- a/src/dotty/tools/dotc/typer/Typer.scala +++ b/src/dotty/tools/dotc/typer/Typer.scala @@ -930,6 +930,8 @@ class Typer extends Namer with Applications with Implicits { */ def adapt(tree: Tree, pt: Type)(implicit ctx: Context): Tree = ctx.traceIndented(i"adapting $tree of type ${tree.tpe} to $pt", show = false) { + def methodStr = err.refStr(methPart(tree).tpe) + def adaptOverloaded(ref: TermRef) = { val altDenots = ref.denot.alternatives val alts = altDenots map (alt => @@ -957,12 +959,11 @@ class Typer extends Namer with Applications with Implicits { def adaptToArgs(tp: Type, pt: FunProto) = tp match { case _: MethodType => tree case _ => tryInsertApply(tree, pt) { - def fn = err.refStr(methPart(tree).tpe) val more = tree match { case Apply(_, _) => " more" case _ => "" } - _ => errorTree(tree, i"$fn does not take$more parameters") + _ => errorTree(tree, i"$methodStr does not take$more parameters") } } @@ -970,7 +971,12 @@ class Typer extends Namer with Applications with Implicits { case tp: ExprType => adapt(tree.withType(tp.resultType), pt) case tp: ImplicitMethodType => - val args = tp.paramTypes map (inferImplicit(_, EmptyTree, tree.pos)) + val args = (tp.paramNames, tp.paramTypes).zipped map { (pname, formal) => + val arg = inferImplicit(formal, EmptyTree, tree.pos.endPos) + if (arg.isEmpty) + ctx.error(i"no implicit argument of type $formal found for parameter $pname of $methodStr", tree.pos.endPos) + arg + } adapt(tpd.Apply(tree, args), pt) case tp: MethodType => if (defn.isFunctionType(pt) && !tree.symbol.isConstructor) @@ -979,7 +985,7 @@ class Typer extends Namer with Applications with Implicits { adapt(tpd.Apply(tree, Nil), pt) else errorTree(tree, - i"""missing arguments for ${tree.symbol} + i"""missing arguments for $methodStr |follow this method with `_' if you want to treat it as a partially applied function""".stripMargin) case _ => if (tp <:< pt) tree -- cgit v1.2.3