From a2c0e29c9e2f8f06e9499c02ebd6e2c3666a0709 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 23 Jul 2013 11:42:45 +0200 Subject: Some refactorings and additions on error reporting. Also, removed redundant Trees. prefixes in patterns. --- src/dotty/tools/dotc/ast/TypedTrees.scala | 3 + src/dotty/tools/dotc/typer/Applications.scala | 16 ++++- src/dotty/tools/dotc/typer/ErrorReporting.scala | 66 ++++++++++++++++++ src/dotty/tools/dotc/typer/EtaExpansion.scala | 22 +++--- src/dotty/tools/dotc/typer/Typer.scala | 91 ++++++++----------------- 5 files changed, 122 insertions(+), 76 deletions(-) create mode 100644 src/dotty/tools/dotc/typer/ErrorReporting.scala (limited to 'src/dotty/tools') diff --git a/src/dotty/tools/dotc/ast/TypedTrees.scala b/src/dotty/tools/dotc/ast/TypedTrees.scala index 2e9944df3..c3eadeb8d 100644 --- a/src/dotty/tools/dotc/ast/TypedTrees.scala +++ b/src/dotty/tools/dotc/ast/TypedTrees.scala @@ -14,6 +14,9 @@ object tpd extends Trees.Instance[Type] { if (sym.privateWithin.exists) sym.privateWithin.asType.name else tpnme.EMPTY, sym.annotations map (_.tree)) + def Modifiers(flags: FlagSet = EmptyFlags, privateWithin: TypeName = tpnme.EMPTY, annotations: List[Tree] = Nil) = + Trees.Modifiers(flags, privateWithin, annotations) + def Ident(tp: NamedType)(implicit ctx: Context): Ident = Trees.Ident(tp.name).withType(tp.underlyingIfRepeated).checked diff --git a/src/dotty/tools/dotc/typer/Applications.scala b/src/dotty/tools/dotc/typer/Applications.scala index 663e24415..f4b8d8b12 100644 --- a/src/dotty/tools/dotc/typer/Applications.scala +++ b/src/dotty/tools/dotc/typer/Applications.scala @@ -59,6 +59,18 @@ object Applications { case et: ExprType => et.resultType case _ => tp } + + case class FunProtoType(args: List[untpd.Tree], override val resultType: Type, typer: Typer)(implicit ctx: Context) extends UncachedGroundType { + private var myTypedArgs: List[tpd.Tree] = null + + def argsAreTyped: Boolean = myTypedArgs != null + + def typedArgs: List[tpd.Tree] = { + if (myTypedArgs == null) + myTypedArgs = args mapconserve (typer.typed(_)) + myTypedArgs + } + } } import Applications._ @@ -311,7 +323,7 @@ trait Applications extends Compatibility{ self: Typer => * must fit the given expected result type. */ def constrainResult(mt: Type, pt: Type): Boolean = pt match { - case FunProtoType(_, result) => + case FunProtoType(_, result, _) => mt match { case mt: MethodType if !mt.isDependent => constrainResult(mt.resultType, pt.resultType) @@ -595,7 +607,7 @@ trait Applications extends Compatibility{ self: Typer => alts filter (isApplicableToTypes(_, argTypes, resultType)) val candidates = pt match { - case pt @ FunProtoType(args, resultType) => + case pt @ FunProtoType(args, resultType, _) => val numArgs = args.length def sizeFits(alt: TermRef, tp: Type): Boolean = tp match { diff --git a/src/dotty/tools/dotc/typer/ErrorReporting.scala b/src/dotty/tools/dotc/typer/ErrorReporting.scala new file mode 100644 index 000000000..ef6184394 --- /dev/null +++ b/src/dotty/tools/dotc/typer/ErrorReporting.scala @@ -0,0 +1,66 @@ +package dotty.tools +package dotc +package typer + +import ast._ +import core._ +import Trees._ +import Types._, Contexts._, Decorators._, Denotations._ +import Applications._ +import util.Positions._ + +object ErrorReporting { + + import tpd._ + + def errorTree(tree: Trees.Tree[_], msg: => String)(implicit ctx: Context): tpd.Tree = { + ctx.error(msg, tree.pos) + tree withType ErrorType + } + + class Errors(implicit ctx: Context) { + + def expectedTypeStr(tp: Type): String = tp match { + case tp: FunProtoType => + val result = tp.resultType match { + case tp: WildcardType => "" + case tp => s"and expected result type $tp" + } + s"arguments (${tp.typedArgs map (_.tpe.show) mkString ", "})$result" + case _ => + s"expected type ${tp.show}" + } + + def anonymousTypeMemberStr(tpe: Type) = { + val kind = tpe match { + case _: TypeBounds => "type with bounds" + case _: PolyType | _: MethodType => "method" + case _ => "value of type" + } + s"$kind $tpe" + } + + def overloadedAltsStr(alts: List[SingleDenotation]) = + s"overloaded alternatives of ${denotStr(alts.head)} with types\n" + + s" ${alts map (_.info) mkString "\n "}" + + def denotStr(denot: Denotation): String = + if (denot.isOverloaded) overloadedAltsStr(denot.alternatives) + else if (denot.symbol.exists) denot.symbol.showLocated + else anonymousTypeMemberStr(denot.info) + + def refStr(tp: Type): String = tp match { + case tp: NamedType => denotStr(tp.denot) + case _ => anonymousTypeMemberStr(tp) + } + + def typeMismatch(tree: Tree, pt: Type): Tree = + errorTree(tree, + s"""type mismatch: + | found : ${tree.tpe.show} + | required: ${pt.show}""".stripMargin) + + } + + def err(implicit ctx: Context): Errors = new Errors +} \ No newline at end of file diff --git a/src/dotty/tools/dotc/typer/EtaExpansion.scala b/src/dotty/tools/dotc/typer/EtaExpansion.scala index dffe8aca9..48b7a063e 100644 --- a/src/dotty/tools/dotc/typer/EtaExpansion.scala +++ b/src/dotty/tools/dotc/typer/EtaExpansion.scala @@ -45,15 +45,15 @@ object EtaExpansion { } def liftApp(defs: mutable.ListBuffer[Tree], tree: Tree)(implicit ctx: Context): Tree = tree match { - case Trees.Apply(fn, args) => + case Apply(fn, args) => tree.derivedApply(liftApp(defs, fn), liftArgs(defs, fn.tpe, args)) - case Trees.TypeApply(fn, targs) => + case TypeApply(fn, targs) => tree.derivedTypeApply(liftApp(defs, fn), targs) - case Trees.Select(pre, name) => + case Select(pre, name) => tree.derivedSelect(lift(defs, pre), name) - case Trees.Ident(name) => + case Ident(name) => lift(defs, tree) - case Trees.Block(stats, expr) => + case Block(stats, expr) => liftApp(defs ++= stats, expr) case _ => tree @@ -79,21 +79,21 @@ object EtaExpansion { val paramsArgs: List[(untpd.ValDef, untpd.Tree)] = (paramNames, paramTypes).zipped.map { (name, tp) => val droppedStarTpe = defn.underlyingOfRepeated(tp) - val param = Trees.ValDef( - Trees.Modifiers(Param), name, + val param = ValDef( + Modifiers(Param), name, untpd.TypedSplice(TypeTree(droppedStarTpe)), untpd.EmptyTree) - var arg: untpd.Tree = Trees.Ident(name) + var arg: untpd.Tree = Ident(name) if (defn.isRepeatedParam(tp)) - arg = Trees.Typed(arg, Trees.Ident(tpnme.WILDCARD_STAR)) + arg = Typed(arg, Ident(tpnme.WILDCARD_STAR)) (param, arg) } val (params, args) = paramsArgs.unzip - untpd.Function(params, Trees.Apply(untpd.TypedSplice(tree), args)) + untpd.Function(params, Apply(untpd.TypedSplice(tree), args)) } val defs = new mutable.ListBuffer[Tree] val tree1 = liftApp(defs, tree) - Trees.Block(defs.toList map untpd.TypedSplice, expand(tree1)) + Block(defs.toList map untpd.TypedSplice, expand(tree1)) } */ diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala index a82cf1eda..8d936743f 100644 --- a/src/dotty/tools/dotc/typer/Typer.scala +++ b/src/dotty/tools/dotc/typer/Typer.scala @@ -18,6 +18,8 @@ import Names._ import NameOps._ import Flags._ import Decorators._ +import ErrorReporting._ +import Applications.FunProtoType import EtaExpansion.etaExpand import util.Positions._ import util.SourcePosition @@ -165,9 +167,9 @@ class Typer extends Namer with Applications with Implicits { found } selectors match { - case Trees.Pair(Trees.Ident(from), Trees.Ident(`name`)) :: rest => + case Pair(Ident(from), Ident(`name`)) :: rest => checkUnambiguous(typedSelection(site, name, tree.pos)) - case Trees.Ident(`name`) :: rest => + case Ident(`name`) :: rest => checkUnambiguous(typedSelection(site, name, tree.pos)) case _ :: rest => namedImportRef(site, rest) @@ -248,28 +250,8 @@ class Typer extends Namer with Applications with Implicits { tree.withType(ownType).derivedSelect(qual1, tree.name) } - case class FunProtoType(args: List[untpd.Tree], override val resultType: Type)(implicit ctx: Context) extends UncachedGroundType { - private var myTypedArgs: List[tpd.Tree] = null - - def argsAreTyped: Boolean = myTypedArgs != null - - def typedArgs: List[tpd.Tree] = { - if (myTypedArgs == null) - myTypedArgs = args mapconserve (typed(_)) - myTypedArgs - } - - def expected: String = { - val result = resultType match { - case tp: WildcardType => "" - case tp => s"and expected result type $tp" - } - s"arguments (${typedArgs map (_.tpe.show) mkString ", "})$result" - } - } - def typedApply(tree: untpd.Apply, pt: Type)(implicit ctx: Context): Tree = { - val proto = new FunProtoType(tree.args, pt) + val proto = new FunProtoType(tree.args, pt, this) val fun1 = typedExpr(tree.fun, proto) TreeInfo.methPart(fun1).tpe match { case funRef: TermRef => @@ -288,14 +270,14 @@ class Typer extends Namer with Applications with Implicits { def typedModifiers(mods: untpd.Modifiers)(implicit ctx: Context): Modifiers = { val annotations1 = mods.annotations mapconserve typedAnnotation if (annotations1 eq mods.annotations) mods.asInstanceOf[Modifiers] - else Trees.Modifiers(mods.flags, mods.privateWithin, annotations1) + else Modifiers(mods.flags, mods.privateWithin, annotations1) } def typedAnnotation(annot: untpd.Tree)(implicit ctx: Context): Tree = typed(annot, defn.AnnotationClass.typeConstructor) def typedValDef(vdef: untpd.ValDef, sym: Symbol)(implicit ctx: Context) = { - val Trees.ValDef(mods, name, tpt, rhs) = vdef + val ValDef(mods, name, tpt, rhs) = vdef val mods1 = typedModifiers(mods) val tpt1 = typedType(tpt) val rhs1 = typedExpr(rhs, tpt1.tpe) @@ -304,7 +286,7 @@ class Typer extends Namer with Applications with Implicits { } def typedDefDef(ddef: untpd.DefDef, sym: Symbol)(implicit ctx: Context) = { - val Trees.DefDef(mods, name, tparams, vparamss, tpt, rhs) = ddef + val DefDef(mods, name, tparams, vparamss, tpt, rhs) = ddef val mods1 = typedModifiers(mods) val tparams1 = tparams mapconserve (typed(_).asInstanceOf[TypeDef]) val vparamss1 = vparamss.mapconserve(_ mapconserve (typed(_).asInstanceOf[ValDef])) @@ -315,14 +297,14 @@ class Typer extends Namer with Applications with Implicits { } def typedTypeDef(tdef: untpd.TypeDef, sym: Symbol)(implicit ctx: Context): TypeDef = { - val Trees.TypeDef(mods, name, rhs) = tdef + val TypeDef(mods, name, rhs) = tdef val mods1 = typedModifiers(mods) val rhs1 = typedType(rhs) tdef.withType(sym.symRef).derivedTypeDef(mods1, name, rhs1) } def typedClassDef(cdef: untpd.TypeDef, cls: ClassSymbol)(implicit ctx: Context) = { - val Trees.TypeDef(mods, name, impl @ Template(constr, parents, self, body)) = cdef + val TypeDef(mods, name, impl @ Template(constr, parents, self, body)) = cdef val mods1 = typedModifiers(mods) val constr1 = typed(constr).asInstanceOf[DefDef] val parents1 = parents mapconserve (typed(_)) @@ -444,19 +426,6 @@ class Typer extends Namer with Applications with Implicits { case _ => fallBack } - def errorTree(tree: Trees.Tree[_], msg: => String)(implicit ctx: Context): tpd.Tree = { - ctx.error(msg, tree.pos) - tree withType ErrorType - } - - def expected(tp: Type)(implicit ctx: Context): String = tp match { - case tp: FunProtoType => tp.expected - case _ => s"expected type ${tp.show}" - } - - def summarize(tpe: Type): String = ??? - - /** * (-1) For expressions with annotated types, let AnnotationCheckers decide what to do * (0) Convert expressions with constant types to literals (unless in interactive/scaladoc mode) @@ -498,41 +467,37 @@ class Typer extends Namer with Applications with Implicits { */ def adapt(tree: Tree, pt: Type)(implicit ctx: Context): Tree = { - def overloadError(prefix: String, suffix: String, alts: List[TermRef]) = - errorTree(tree, - s"""$prefix alternatives of ${alts.head.show} with types - | ${alts map (_.info) mkString "\n "} - |$suffix ${expected(pt)}""".stripMargin) - - def notAFunctionError() = { - val fn = summarize(TreeInfo.methPart(tree).tpe) - val more = tree match { - case Apply(_, _) => " more" - case _ => "" - } - errorTree(tree, s"$fn does not take$more parameters") - } - - def typeMismatch(tree: Tree, pt: Type)(implicit ctx: Context): Tree = ??? - def adaptOverloaded(ref: TermRef) = { - val alts = ref.denot.alternatives map (alt => + val altDenots = ref.denot.alternatives + val alts = altDenots map (alt => TermRef.withSym(ref.prefix, alt.symbol.asTerm)) + def expectedStr = err.expectedTypeStr(pt) resolveOverloaded(alts, pt) match { case alt :: Nil => adapt(tree.withType(alt), pt) case Nil => tryInsertApplyIfFunProto(tree, pt) { - overloadError("none of the overloaded", "match", alts) + errorTree(tree, + s"""none of the ${err.overloadedAltsStr(altDenots)} + |match $expectedStr""".stripMargin) } case alts => - overloadError("Ambiguous overload. The ", "both match", alts take 2) + errorTree(tree, + s"""Ambiguous overload. The ${err.overloadedAltsStr(altDenots take 2)} + |both match $expectedStr""".stripMargin) } } def adaptToArgs(tp: Type, pt: FunProtoType) = tp match { case _: MethodType => tree - case _ => tryInsertApply(tree, pt) { notAFunctionError() } + case _ => tryInsertApply(tree, pt) { + def fn = err.refStr(TreeInfo.methPart(tree).tpe) + val more = tree match { + case Apply(_, _) => " more" + case _ => "" + } + errorTree(tree, s"$fn does not take$more parameters") + } } def adaptNoArgs(tp: Type) = tp match { @@ -563,7 +528,7 @@ class Typer extends Namer with Applications with Implicits { val adapted = inferView(tree, pt) if (adapted ne EmptyTree) return adapted } - typeMismatch(tree, pt) + err.typeMismatch(tree, pt) } tree.tpe.widen match { -- cgit v1.2.3