diff options
Diffstat (limited to 'src/compiler/scala/tools/nsc/typechecker/Infer.scala')
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Infer.scala | 303 |
1 files changed, 167 insertions, 136 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index 26e4da5d79..354eb52913 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -189,7 +189,7 @@ trait Infer { private val stdErrorValue = stdErrorClass.newErrorValue(nme.ERROR) /** The context-dependent inferencer part */ - class Inferencer(context: Context) extends InferencerErrorTrees { + class Inferencer(context: Context) { /* -- Error Messages --------------------------------------------------- */ def setError[T <: Tree](tree: T): T = { def name = newTermName("<error: " + tree.symbol + ">") @@ -203,20 +203,19 @@ trait Infer { tree setType ErrorType } - protected def getContext = context - def error(pos: Position, msg: String) { context.error(pos, msg) } -/* def makeErrorTree(tree: Tree, msg: String): Tree = { + def errorTree(tree: Tree, msg: String): Tree = { if (!tree.isErroneous) error(tree.pos, msg) setError(tree) - }*/ + } def typeError(pos: Position, found: Type, req: Type) { if (!found.isErroneous && !req.isErroneous) { error(pos, withAddendum(pos)(typeErrorMsg(found, req))) + if (settings.explaintypes.value) explainTypes(found, req) } @@ -229,8 +228,6 @@ trait Infer { "type mismatch" + foundReqMsg(found, req) + missingArgsMsg } - // TODO: replace with standard Error tree - // currently only used in adapt in Typers def typeErrorTree(tree: Tree, found: Type, req: Type): Tree = { // If the expected type is a refinement type, and the found type is a refinement or an anon // class, we can greatly improve the error message by retyping the tree to recover the actual @@ -290,7 +287,7 @@ trait Infer { Console.println(tree) Console.println("" + pre + " " + sym.owner + " " + context.owner + " " + context.outer.enclClass.owner + " " + sym.owner.thisType + (pre =:= sym.owner.thisType)) } - AccessError(tree, sym, pre, context.enclClass.owner, + new AccessError(tree, sym, pre, if (settings.check.isDefault) analyzer.lastAccessCheckDetails else @@ -317,17 +314,11 @@ trait Infer { if (settings.debug.value) ex.printStackTrace val sym2 = underlying(sym1) val itype = pre.memberType(sym2) - return AccessError(tree, sym, pre, context.enclClass.owner, + new AccessError(tree, sym, pre, "\n because its instance type "+itype+ (if ("malformed type: "+itype.toString==ex.msg) " is malformed" - else " contains a "+ex.msg)) - -// enabling the following TypeError case -// crashes a few examples because there are situations (like in NamesDefaults) -// where CyclicReference is expected -// case ex: TypeError => -// return TypeErrorTree(tree, ex)(context) - + else " contains a "+ex.msg)).emit() + ErrorType } if (pre.isInstanceOf[SuperType]) owntype = owntype.substSuper(pre, site.symbol.thisType) @@ -920,9 +911,7 @@ trait Infer { false } - /** - * Todo: Try to make isApplicable always safe (i.e. not cause TypeErrors). - * The chance of TypeErrors should be reduced through error trees + /** Todo: Try to make isApplicable always safe (i.e. not cause TypeErrors). */ private[typechecker] def isApplicableSafe(undetparams: List[Symbol], ftpe: Type, argtpes0: List[Type], pt: Type): Boolean = { @@ -1103,20 +1092,37 @@ trait Infer { */ /** error if arguments not within bounds. */ def checkBounds(pos: Position, pre: Type, owner: Symbol, - tparams: List[Symbol], targs: List[Type], prefix: String): Option[ErrorTree] = { + tparams: List[Symbol], targs: List[Type], prefix: String) = { //@M validate variances & bounds of targs wrt variances & bounds of tparams //@M TODO: better place to check this? //@M TODO: errors for getters & setters are reported separately val kindErrors = checkKindBounds(tparams, targs, pre, owner) - if(!kindErrors.isEmpty) { - if (targs contains WildcardType) None - else Some(KindBoundErrors(pos, prefix, targs, tparams, kindErrors)) - } else if (!isWithinBounds(pre, owner, tparams, targs)) { - if (!(targs exists (_.isErroneous)) && !(tparams exists (_.isErroneous))) - Some(NotWithinBounds(pos, prefix, targs, tparams, kindErrors)) - else None - } else None + if (!kindErrors.isEmpty) { + if (targs contains WildcardType) () + else error(pos, + prefix + "kinds of the type arguments " + targs.mkString("(", ",", ")") + + " do not conform to the expected kinds of the type parameters "+ + tparams.mkString("(", ",", ")") + tparams.head.locationString+ "." + + kindErrors.toList.mkString("\n", ", ", "")) + } + else if (!isWithinBounds(pre, owner, tparams, targs)) { + if (!(targs exists (_.isErroneous)) && !(tparams exists (_.isErroneous))) { + //val bounds = instantiatedBounds(pre, owner, tparams, targs)//DEBUG + //println("bounds = "+bounds+", targs = "+targs+", targclasses = "+(targs map (_.getClass))+", parents = "+(targs map (_.parents))) + //println(List.map2(bounds, targs)((bound, targ) => bound containsType targ)) + error(pos, + prefix + "type arguments " + targs.mkString("[", ",", "]") + + " do not conform to " + tparams.head.owner + "'s type parameter bounds " + + (tparams map (_.defString)).mkString("[", ",", "]")) + if (settings.explaintypes.value) { + val bounds = tparams map (tp => tp.info.instantiateTypeParams(tparams, targs).bounds) + (targs, bounds).zipped foreach ((targ, bound) => explainTypes(bound.lo, targ)) + (targs, bounds).zipped foreach ((targ, bound) => explainTypes(targ, bound.hi)) + () + } + } + } } @@ -1160,7 +1166,7 @@ trait Infer { * first to `strictPt` and then, if this fails, to `lenientPt`. If both * attempts fail, an error is produced. */ - def inferArgumentInstance(tree: Tree, undetparams: List[Symbol], strictPt: Type, lenientPt: Type) = { + def inferArgumentInstance(tree: Tree, undetparams: List[Symbol], strictPt: Type, lenientPt: Type) { printInference( ptBlock("inferArgumentInstance", "tree" -> tree, @@ -1174,8 +1180,8 @@ trait Infer { if ((targs eq null) || !(tree.tpe.subst(undetparams, targs) <:< strictPt)) { targs = exprTypeArgs(undetparams, tree.tpe, lenientPt) } - printInference("[inferArgumentInstance] finished, targs = " + targs) substExpr(tree, undetparams, targs, lenientPt) + printInference("[inferArgumentInstance] finished, targs = " + targs) } /** Infer type arguments `targs` for `tparams` of polymorphic expression in `tree`, given prototype `pt`. @@ -1183,7 +1189,7 @@ trait Infer { * Substitute `tparams` to `targs` in `tree`, after adjustment by `adjustTypeArgs`, returning the type parameters that were not determined * If passed, infers against specified type `treeTp` instead of `tree.tp`. */ - def inferExprInstance(tree: Tree, tparams: List[Symbol], pt: Type = WildcardType, treeTp0: Type = null, keepNothings: Boolean = true, useWeaklyCompatible: Boolean = false): (Option[ErrorTree], List[Symbol]) = { + def inferExprInstance(tree: Tree, tparams: List[Symbol], pt: Type = WildcardType, treeTp0: Type = null, keepNothings: Boolean = true, useWeaklyCompatible: Boolean = false): List[Symbol] = { val treeTp = if(treeTp0 eq null) tree.tpe else treeTp0 // can't refer to tree in default for treeTp0 printInference( ptBlock("inferExprInstance", @@ -1196,7 +1202,8 @@ trait Infer { val targs = exprTypeArgs(tparams, treeTp, pt, useWeaklyCompatible) if (keepNothings || (targs eq null)) { //@M: adjustTypeArgs fails if targs==null, neg/t0226 - (substExpr(tree, tparams, targs, pt), List()) + substExpr(tree, tparams, targs, pt) + List() } else { val AdjustedTypeArgs.Undets(okParams, okArgs, leftUndet) = adjustTypeArgs(tparams, targs) printInference( @@ -1206,7 +1213,8 @@ trait Infer { "leftUndet" -> leftUndet ) ) - (substExpr(tree, okParams, okArgs, pt), leftUndet) + substExpr(tree, okParams, okArgs, pt) + leftUndet } } @@ -1219,15 +1227,13 @@ trait Infer { * @param pt ... */ private def substExpr(tree: Tree, undetparams: List[Symbol], - targs: List[Type], pt: Type): Option[ErrorTree] = { + targs: List[Type], pt: Type) { if (targs eq null) { if (!tree.tpe.isErroneous && !pt.isErroneous) - Some(PolymorphicExpressionInstantiationError(tree, undetparams, pt)) - else - None + error(tree.pos, "polymorphic expression cannot be instantiated to expected type" + + foundReqMsg(polyType(undetparams, skipImplicit(tree.tpe)), pt)) } else { new TreeTypeSubstituter(undetparams, targs).traverse(tree) - None } } @@ -1242,7 +1248,7 @@ trait Infer { * and that thus have not been substituted. */ def inferMethodInstance(fn: Tree, undetparams: List[Symbol], - args: List[Tree], pt0: Type): Either[ErrorTree, List[Symbol]] = fn.tpe match { + args: List[Tree], pt0: Type): List[Symbol] = fn.tpe match { case MethodType(params0, _) => printInference( ptBlock("inferMethodInstance", @@ -1262,32 +1268,31 @@ trait Infer { val AdjustedTypeArgs.AllArgsAndUndets(okparams, okargs, allargs, leftUndet) = methTypeArgs(undetparams, formals, restpe, argtpes, pt) - checkBounds(fn.pos, NoPrefix, NoSymbol, undetparams, allargs, "inferred ") match { - case Some(err) => - Left(err) - case _ => - // bounds are ok - val treeSubst = new TreeTypeSubstituter(okparams, okargs) - treeSubst traverseTrees fn :: args - - val result = leftUndet match { - case Nil => Nil - case xs => - // #3890 - val xs1 = treeSubst.typeSubst mapOver xs - if (xs ne xs1) - new TreeSymSubstTraverser(xs, xs1) traverseTrees fn :: args - - xs1 - } - if (result.nonEmpty) - printInference("inferMethodInstance, still undetermined: " + result) + checkBounds(fn.pos, NoPrefix, NoSymbol, undetparams, allargs, "inferred ") + val treeSubst = new TreeTypeSubstituter(okparams, okargs) + treeSubst traverseTrees fn :: args - Right(result) + val result = leftUndet match { + case Nil => Nil + case xs => + // #3890 + val xs1 = treeSubst.typeSubst mapOver xs + if (xs ne xs1) + new TreeSymSubstTraverser(xs, xs1) traverseTrees fn :: args + + xs1 } + if (result.nonEmpty) + printInference("inferMethodInstance, still undetermined: " + result) + + result } catch ifNoInstance { msg => - Left(NoMethodInstanceError(fn, args, msg)) + errorTree(fn, "no type parameters for " + + applyErrorMsg(fn, " exist so that it can be applied to arguments ", args map (_.tpe.widen), WildcardType) + + "\n --- because ---\n" + msg + ) + Nil } } @@ -1312,7 +1317,7 @@ trait Infer { * @param undetparams the undetermined type parameters * @param pt the expected result type of the instance */ - def inferConstructorInstance(tree: Tree, undetparams: List[Symbol], pt0: Type): Option[ErrorTree] = { + def inferConstructorInstance(tree: Tree, undetparams: List[Symbol], pt0: Type) { val pt = widen(pt0) //println("infer constr inst "+tree+"/"+undetparams+"/"+pt0) var restpe = tree.tpe.finalResultType @@ -1327,14 +1332,17 @@ trait Infer { // checkBounds(tree.pos, NoPrefix, NoSymbol, undetparams, targs, "inferred ") // no checkBounds here. If we enable it, test bug602 fails. new TreeTypeSubstituter(undetparams, targs).traverse(tree) - None - } catch ifNoInstance{ msg => - Some(NoConstructorInstanceError(tree, restpe, pt, msg)) + } catch { + case ex: NoInstance => + errorTree(tree, "constructor of type " + restpe + + " cannot be uniquely instantiated to expected type " + pt + + "\n --- because ---\n" + ex.getMessage()) } def instError = { if (settings.debug.value) Console.println("ici " + tree + " " + undetparams + " " + pt) if (settings.explaintypes.value) explainTypes(restpe.instantiateTypeParams(undetparams, tvars), pt) - Some(ConstrInstantiationError(tree, restpe, pt)) + errorTree(tree, "constructor cannot be instantiated to expected type" + + foundReqMsg(restpe, pt)) } if (restpe.instantiateTypeParams(undetparams, tvars) <:< pt) { computeArgs @@ -1352,7 +1360,6 @@ trait Infer { val pt1 = pt.instantiateTypeParams(ptparams, ptvars) if (isPopulated(restpe, pt1)) { ptvars foreach instantiateTypeVar - None } else { if (settings.debug.value) Console.println("no instance: "); instError } } else { if (settings.debug.value) Console.println("not a subtype " + restpe.instantiateTypeParams(undetparams, tvars) + " of " + ptWithWildcards); instError } } else { if (settings.debug.value) Console.println("not fully defined: " + pt); instError } @@ -1405,12 +1412,11 @@ trait Infer { } } - def checkCheckable(pos: Position, tp: Type, kind: String): Option[ErrorTree] = { + def checkCheckable(pos: Position, tp: Type, kind: String) { def patternWarning(tp0: Type, prefix: String) = { context.unit.uncheckedWarning(pos, prefix+tp0+" in type "+kind+tp+" is unchecked since it is eliminated by erasure") } - def check(tp: Type, bound: List[Symbol]): Option[ErrorTree] = { - implicit def listErrorsToPending(l: List[ErrorTree]): Option[ErrorTree] = if (l.isEmpty) None else Some(PendingErrors(l)) + def check(tp: Type, bound: List[Symbol]) { def isLocalBinding(sym: Symbol) = sym.isAbstractType && ((bound contains sym) || @@ -1422,38 +1428,36 @@ trait Infer { case SingleType(pre, _) => check(pre, bound) case TypeRef(pre, sym, args) => - val checkForSymAndArgs: Option[ErrorTree] = if (sym.isAbstractType) { + if (sym.isAbstractType) { if (!isLocalBinding(sym)) patternWarning(tp, "abstract type ") - None } else if (sym.isAliasType) { check(tp.normalize, bound) } else if (sym == NothingClass || sym == NullClass || sym == AnyValClass) { - Some(TypePatternOrIsInstanceTestError(pos, tp)) + error(pos, "type "+tp+" cannot be used in a type pattern or isInstanceOf test") } else { - args.map( arg => { + for (arg <- args) { if (sym == ArrayClass) check(arg, bound) - else if (arg.typeArgs.nonEmpty) None // avoid spurious warnings with higher-kinded types - else {arg match { + else if (arg.typeArgs.nonEmpty) () // avoid spurious warnings with higher-kinded types + else arg match { case TypeRef(_, sym, _) if isLocalBinding(sym) => - + ; case _ => patternWarning(arg, "non variable type-argument ") - }; None} - }).flatten + } + } } - List(checkForSymAndArgs, check(pre, bound)).flatten + check(pre, bound) case RefinedType(parents, decls) => - if (decls.isEmpty) parents.map(p => check(p, bound)).flatten - else { patternWarning(tp, "refinement "); None } + if (decls.isEmpty) for (p <- parents) check(p, bound) + else patternWarning(tp, "refinement ") case ExistentialType(quantified, tp1) => check(tp1, bound ::: quantified) case ThisType(_) => - None + ; case NoPrefix => - None + ; case _ => patternWarning(tp, "type ") - None } } check(tp, List()) @@ -1476,7 +1480,7 @@ trait Infer { } } - def inferTypedPattern(pos: Position, pattp: Type, pt0: Type): Either[ErrorTree, Type] = { + def inferTypedPattern(pos: Position, pattp: Type, pt0: Type): Type = { val pt = widen(pt0) val ptparams = freeTypeParamsOfTerms.collect(pt) val tpparams = freeTypeParamsOfTerms.collect(pattp) @@ -1489,13 +1493,9 @@ trait Infer { * and is a "final type", meaning final + invariant in all type parameters. */ if (pt.isFinalType && ptparams.isEmpty && !ptMatchesPattp) - return Left(IncompatibleScrutineeTypeError(pos, pattp, pt)) + error(pos, "scrutinee is incompatible with pattern type" + foundReqMsg(pattp, pt)) - checkCheckable(pos, pattp, "pattern ") match { - case Some(err) => - return Left(err) - case _ => () - } + checkCheckable(pos, pattp, "pattern ") if (pattp <:< pt) () else { debuglog("free type params (1) = " + tpparams) @@ -1517,8 +1517,10 @@ trait Infer { // fail if we didn't allow for pattpMatchesPt. if (isPopulated(tp, pt1) && isInstantiatable(tvars ++ ptvars) || pattpMatchesPt) ptvars foreach instantiateTypeVar - else - return Left(IncompletePatternTypeError(pos, pattp, pt)) + else { + error(pos, "pattern type is incompatible with expected type" + foundReqMsg(pattp, pt)) + return pattp + } } tvars foreach instantiateTypeVar } @@ -1526,22 +1528,43 @@ trait Infer { * we have to flip the arguments so the expected type is treated as more * general when calculating the intersection. See run/bug2755.scala. */ - if (tpparams.isEmpty && ptparams.nonEmpty) Right(intersect(pattp, pt)) - else Right(intersect(pt, pattp)) + if (tpparams.isEmpty && ptparams.nonEmpty) intersect(pattp, pt) + else intersect(pt, pattp) } - def inferModulePattern(pat: Tree, pt: Type): Option[ErrorTree] = + def inferModulePattern(pat: Tree, pt: Type) = if (!(pat.tpe <:< pt)) { val ptparams = freeTypeParamsOfTerms.collect(pt) debuglog("free type params (2) = " + ptparams) val ptvars = ptparams map freshVar val pt1 = pt.instantiateTypeParams(ptparams, ptvars) - if (pat.tpe <:< pt1) { + if (pat.tpe <:< pt1) ptvars foreach instantiateTypeVar - None - } else - Some(PatternTypeIncompatibleWithPtError(pat, pt1, pt)) - } else None + else { + val sym = pat.tpe.typeSymbol + val clazz = sym.companionClass + val addendum = ( + if (sym.isModuleClass && clazz.isCaseClass && (clazz isSubClass pt1.typeSymbol)) { + // TODO: move these somewhere reusable. + val typeString = clazz.typeParams match { + case Nil => "" + clazz.name + case xs => xs map (_ => "_") mkString (clazz.name + "[", ",", "]") + } + val caseString = ( + clazz.caseFieldAccessors + map (_ => "_") // could use the actual param names here + mkString (clazz.name + "(", ",", ")") + ) + ( + "\nNote: if you intended to match against the class, try `case _: " + + typeString + "` or `case " + caseString + "`" + ) + } + else "" + ) + error(pat.pos, "pattern type is incompatible with expected type"+foundReqMsg(pat.tpe, pt) + addendum) + } + } object toOrigin extends TypeMap { def apply(tp: Type): Type = tp match { @@ -1608,7 +1631,7 @@ trait Infer { * If several alternatives match `pt`, take parameterless one. * If no alternative matches `pt`, take the parameterless one anyway. */ - def inferExprAlternative(tree: Tree, pt: Type): Option[ErrorTree] = tree.tpe match { + def inferExprAlternative(tree: Tree, pt: Type): Unit = tree.tpe match { case OverloadedType(pre, alts) => tryTwice { val alts0 = alts filter (alt => isWeaklyCompatible(pre.memberType(alt), pt)) val secondTry = alts0.isEmpty @@ -1639,27 +1662,24 @@ trait Infer { case _ => } } - Some(NoBestExprAlternativeError(tree, pt)) + typeErrorTree(tree, tree.symbol.tpe, pt) } else if (!competing.isEmpty) { if (secondTry) { - Some(NoBestExprAlternativeError(tree, pt)) + typeErrorTree(tree, tree.symbol.tpe, pt) } else { if (!pt.isErroneous) - Some(AmbiguousExprAlternativeError(tree, pre, best, competing.head, pt)) - else - Some(NullErrorTree) // already reported + context.ambiguousError(tree.pos, pre, best, competing.head, "expected type " + pt) + setError(tree) } } else { // val applicable = alts1 filter (alt => // global.typer.infer.isWeaklyCompatible(pre.memberType(alt), pt)) // checkNotShadowed(tree.pos, pre, best, applicable) tree.setSymbol(best).setType(pre.memberType(best)) - None } } } - // TODO: remove once error tree refactoring is done @inline private def wrapTypeError(expr: => Boolean): Boolean = try expr catch { case _: TypeError => false } @@ -1723,7 +1743,7 @@ trait Infer { * assignment expression. */ def inferMethodAlternative(tree: Tree, undetparams: List[Symbol], - argtpes: List[Type], pt0: Type, varArgsOnly: Boolean = false): Option[ErrorTree] = tree.tpe match { + argtpes: List[Type], pt0: Type, varArgsOnly: Boolean = false): Unit = tree.tpe match { case OverloadedType(pre, alts) => val pt = if (pt0.typeSymbol == UnitClass) WildcardType else pt0 tryTwice { @@ -1750,22 +1770,24 @@ trait Infer { if (improves(alt, best)) alt else best) val competing = applicable.dropWhile(alt => best == alt || improves(best, alt)) if (best == NoSymbol) { - if (pt == WildcardType) - Some(NoBestMethodAlternativeError(tree, argtpes, pt)) - else + if (pt == WildcardType) { + errorTree(tree, applyErrorMsg(tree, " cannot be applied to ", argtpes, pt)) + } else { inferMethodAlternative(tree, undetparams, argtpes, WildcardType) + } } else if (!competing.isEmpty) { if (!(argtpes exists (_.isErroneous)) && !pt.isErroneous) - Some(AmbiguousMethodAlternativeError(tree, pre, best, competing.head, argtpes, pt)) - else - Some(NullErrorTree) + context.ambiguousError(tree.pos, pre, best, competing.head, + "argument types " + argtpes.mkString("(", ",", ")") + + (if (pt == WildcardType) "" else " and expected result type " + pt)) + setError(tree) + () } else { // checkNotShadowed(tree.pos, pre, best, applicable) tree.setSymbol(best).setType(pre.memberType(best)) - None } } - case _ => None + case _ => } /** Try inference twice, once without views and once with views, @@ -1773,25 +1795,18 @@ trait Infer { * * @param infer ... */ - def tryTwice(infer: => Option[ErrorTree]): Option[ErrorTree] = { + def tryTwice(infer: => Unit) { if (context.implicitsEnabled) { val reportGeneralErrors = context.reportGeneralErrors context.reportGeneralErrors = false - val res = try { - context.withImplicitsDisabled(infer) match { - case Some(err) => - context.reportGeneralErrors = reportGeneralErrors - infer - case ok => ok - } - } catch { + try context.withImplicitsDisabled(infer) + catch { case ex: CyclicReference => throw ex case ex: TypeError => context.reportGeneralErrors = reportGeneralErrors infer } context.reportGeneralErrors = reportGeneralErrors - res } else infer } @@ -1803,10 +1818,10 @@ trait Infer { * @param tree ... * @param nparams ... */ - def inferPolyAlternatives(tree: Tree, argtypes: List[Type]): Option[ErrorTree] = { + def inferPolyAlternatives(tree: Tree, argtypes: List[Type]): Unit = { val OverloadedType(pre, alts) = tree.tpe val sym0 = tree.symbol filter (alt => sameLength(alt.typeParams, argtypes)) - def fail(msg: String) = Some(PolyAlternativeError(tree, msg)) + def fail(msg: String): Unit = error(tree.pos, msg) if (sym0 == NoSymbol) return fail( if (alts exists (_.typeParams.nonEmpty)) @@ -1820,13 +1835,12 @@ trait Infer { else { val sym = sym0 filter (alt => isWithinBounds(pre, alt.owner, alt.typeParams, argtypes)) if (sym == NoSymbol) { - if (argtypes forall (x => !x.isErroneous)) - return fail( + if (argtypes forall (x => !x.isErroneous)) fail( "type arguments " + argtypes.mkString("[", ",", "]") + " conform to the bounds of none of the overloaded alternatives of\n "+sym0+ ": "+sym0.info ) - return None + return } else if (sym.isOverloaded) { val xs = sym.alternatives @@ -1841,7 +1855,24 @@ trait Infer { } // Side effects tree with symbol and type tree setSymbol resSym setType resTpe - None + } + + abstract class TreeForwarder(forwardTo: Tree) extends Tree { + override def pos = forwardTo.pos + override def hasSymbol = forwardTo.hasSymbol + override def symbol = forwardTo.symbol + override def symbol_=(x: Symbol) = forwardTo.symbol = x + } + + case class AccessError(tree: Tree, sym: Symbol, pre: Type, explanation: String) extends TreeForwarder(tree) { + setError(this) + + // @PP: It is improbable this logic shouldn't be in use elsewhere as well. + private def location = if (sym.isClassConstructor) context.enclClass.owner else pre.widen + def emit(): Tree = { + val realsym = underlying(sym) + errorTree(tree, realsym.fullLocationString + " cannot be accessed in " + location + explanation) + } } } } |