From 9c0442984fff7ea9fa7ded05c619d5c1273d85db Mon Sep 17 00:00:00 2001 From: Adriaan Moors Date: Mon, 26 Mar 2012 12:24:05 +0200 Subject: [vpm] error message on missing parameter type for selector-less matches that should yield a function --- .../tools/nsc/typechecker/ContextErrors.scala | 25 ++++------ .../scala/tools/nsc/typechecker/Typers.scala | 54 +++++++++++++--------- 2 files changed, 41 insertions(+), 38 deletions(-) diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala index e37f5784c9..764823d786 100644 --- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala @@ -376,21 +376,16 @@ trait ContextErrors { setError(tree) } - def MissingParameterTypeError(fun: Tree, vparam: ValDef, pt: Type) = { - def anonMessage = ( - "\nThe argument types of an anonymous function must be fully known. (SLS 8.5)" + - "\nExpected type was: " + pt.toLongString - ) - - val suffix = - if (!vparam.mods.isSynthetic) "" - else " for expanded function" + (fun match { - case Function(_, Match(_, _)) => anonMessage - case _ => " " + fun - }) - - issueNormalTypeError(vparam, "missing parameter type" + suffix) - } + def MissingParameterTypeError(fun: Tree, vparam: ValDef, pt: Type) = + if (vparam.mods.isSynthetic) fun match { + case Function(_, Match(_, _)) => MissingParameterTypeAnonMatchError(vparam, pt) + case _ => issueNormalTypeError(vparam, "missing parameter type for expanded function " + fun) + } else issueNormalTypeError(vparam, "missing parameter type") + + def MissingParameterTypeAnonMatchError(vparam: Tree, pt: Type) = + issueNormalTypeError(vparam, "missing parameter type for expanded function\n"+ + "The argument types of an anonymous function must be fully known. (SLS 8.5)\n"+ + "Expected type was: " + pt.toLongString) def ConstructorsOrderError(tree: Tree) = { issueNormalTypeError(tree, "called constructor's definition must precede calling constructor's definition") diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 000e5b78eb..06a7311f79 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -2176,7 +2176,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { def typedMatchAnonFun(tree: Tree, cases: List[CaseDef], mode: Int, pt0: Type, selOverride: Option[(List[ValDef], Tree)] = None) = { val pt = deskolemizeGADTSkolems(pt0) val targs = pt.normalize.typeArgs - val arity = if (isFunctionType(pt)) targs.length - 1 else 1 + val arity = if (isFunctionType(pt)) targs.length - 1 else 1 // TODO pt should always be a (Partial)Function, right? val ptRes = if (targs.isEmpty) WildcardType else targs.last // may not be fully defined val isPartial = pt.typeSymbol == PartialFunctionClass @@ -2188,6 +2188,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { def mkParams(methodSym: Symbol) = { selOverride match { + case None if targs.isEmpty => MissingParameterTypeAnonMatchError(tree, pt); (Nil, EmptyTree) case None => val ps = methodSym newSyntheticValueParams targs.init // is there anything we can do if targs.isEmpty?? val ids = ps map (p => Ident(p.name)) @@ -2213,45 +2214,52 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { anonClass setInfo ClassInfoType(List(ObjectClass.tpe, pt, SerializableClass.tpe), newScope, anonClass) val methodSym = anonClass.newMethod(nme.apply, tree.pos, FINAL) val (paramSyms, selector) = mkParams(methodSym) - methodSym setInfoAndEnter MethodType(paramSyms, AnyClass.tpe) - val methodBodyTyper = newTyper(context.makeNewScope(context.tree, methodSym)) // should use the DefDef for the context's tree, but it doesn't exist yet (we need the typer we're creating to create it) - paramSyms foreach (methodBodyTyper.context.scope enter _) + if (selector eq EmptyTree) EmptyTree + else { + methodSym setInfoAndEnter MethodType(paramSyms, AnyClass.tpe) + + val methodBodyTyper = newTyper(context.makeNewScope(context.tree, methodSym)) // should use the DefDef for the context's tree, but it doesn't exist yet (we need the typer we're creating to create it) + paramSyms foreach (methodBodyTyper.context.scope enter _) - val (selector1, selectorTp, casesAdapted, resTp, doTranslation) = methodBodyTyper.prepareTranslateMatch(selector, cases, mode, ptRes) + val (selector1, selectorTp, casesAdapted, resTp, doTranslation) = methodBodyTyper.prepareTranslateMatch(selector, cases, mode, ptRes) - val formalTypes = paramSyms map (_.tpe) - val parents = - if (isPartial) List(appliedType(AbstractPartialFunctionClass.typeConstructor, List(formalTypes.head, resTp)), SerializableClass.tpe) - else List(appliedType(AbstractFunctionClass(arity).typeConstructor, formalTypes :+ resTp), SerializableClass.tpe) + val formalTypes = paramSyms map (_.tpe) + val parents = + if (isPartial) List(appliedType(AbstractPartialFunctionClass.typeConstructor, List(formalTypes.head, resTp)), SerializableClass.tpe) + else List(appliedType(AbstractFunctionClass(arity).typeConstructor, formalTypes :+ resTp), SerializableClass.tpe) - anonClass setInfo ClassInfoType(parents, newScope, anonClass) - methodSym setInfoAndEnter MethodType(paramSyms, resTp) + anonClass setInfo ClassInfoType(parents, newScope, anonClass) + methodSym setInfoAndEnter MethodType(paramSyms, resTp) - // use apply's parameter since the scrut's type has been widened - def missingCase(scrut_ignored: Tree) = (funThis DOT nme.missingCase) (REF(paramSyms.head)) + // use apply's parameter since the scrut's type has been widened + def missingCase(scrut_ignored: Tree) = (funThis DOT nme.missingCase) (REF(paramSyms.head)) - val body = methodBodyTyper.translateMatch(selector1, selectorTp, casesAdapted, resTp, doTranslation, if (isPartial) Some(missingCase) else None) + val body = methodBodyTyper.translateMatch(selector1, selectorTp, casesAdapted, resTp, doTranslation, if (isPartial) Some(missingCase) else None) - DefDef(methodSym, body) + DefDef(methodSym, body) + } } def isDefinedAtMethod = { val methodSym = anonClass.newMethod(nme._isDefinedAt, tree.pos, FINAL) val (paramSyms, selector) = mkParams(methodSym) - val methodBodyTyper = newTyper(context.makeNewScope(context.tree, methodSym)) // should use the DefDef for the context's tree, but it doesn't exist yet (we need the typer we're creating to create it) - paramSyms foreach (methodBodyTyper.context.scope enter _) - methodSym setInfoAndEnter MethodType(paramSyms, BooleanClass.tpe) + if (selector eq EmptyTree) EmptyTree + else { + val methodBodyTyper = newTyper(context.makeNewScope(context.tree, methodSym)) // should use the DefDef for the context's tree, but it doesn't exist yet (we need the typer we're creating to create it) + paramSyms foreach (methodBodyTyper.context.scope enter _) + methodSym setInfoAndEnter MethodType(paramSyms, BooleanClass.tpe) - val (selector1, selectorTp, casesAdapted, resTp, doTranslation) = methodBodyTyper.prepareTranslateMatch(selector, casesTrue, mode, BooleanClass.tpe) - val body = methodBodyTyper.translateMatch(selector1, selectorTp, casesAdapted, resTp, doTranslation, Some(scrutinee => FALSE_typed)) + val (selector1, selectorTp, casesAdapted, resTp, doTranslation) = methodBodyTyper.prepareTranslateMatch(selector, casesTrue, mode, BooleanClass.tpe) + val body = methodBodyTyper.translateMatch(selector1, selectorTp, casesAdapted, resTp, doTranslation, Some(scrutinee => FALSE_typed)) - DefDef(methodSym, body) + DefDef(methodSym, body) + } } val members = if (!isPartial) List(applyMethod) else List(applyMethod, isDefinedAtMethod) - - typed(Block(List(ClassDef(anonClass, NoMods, List(List()), List(List()), members, tree.pos)), New(anonClass.tpe)), mode, pt) + if (members.head eq EmptyTree) setError(tree) + else typed(Block(List(ClassDef(anonClass, NoMods, List(List()), List(List()), members, tree.pos)), New(anonClass.tpe)), mode, pt) } /** -- cgit v1.2.3