Skip to content

Commit 10845ad

Browse files
committed
Merge pull request scala#2393 from retronym/ticket/7345-2
SI-7345 Refactoring Contexts
2 parents 44625e3 + b36717c commit 10845ad

File tree

14 files changed

+616
-358
lines changed

14 files changed

+616
-358
lines changed

src/compiler/scala/reflect/macros/runtime/Typers.scala

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,10 @@ trait Typers {
5454
wrapper(universe.analyzer.inferImplicit(tree, pt, reportAmbiguous = true, isView = isView, context = context, saveAmbiguousDivergent = !silent, pos = pos)) match {
5555
case failure if failure.tree.isEmpty =>
5656
macroLogVerbose("implicit search has failed. to find out the reason, turn on -Xlog-implicits")
57-
if (context.hasErrors) throw new TypecheckException(context.errBuffer.head.errPos, context.errBuffer.head.errMsg)
58-
universe.EmptyTree
57+
context.firstError match {
58+
case Some(err) => throw new TypecheckException(err.errPos, err.errMsg)
59+
case None => universe.EmptyTree
60+
}
5961
case success =>
6062
success.tree
6163
}

src/compiler/scala/tools/nsc/typechecker/Contexts.scala

Lines changed: 490 additions & 233 deletions
Large diffs are not rendered by default.

src/compiler/scala/tools/nsc/typechecker/Implicits.scala

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,8 @@ trait Implicits {
8181
val implicitSearchContext = context.makeImplicit(reportAmbiguous)
8282
val result = new ImplicitSearch(tree, pt, isView, implicitSearchContext, pos).bestImplicit
8383
if (saveAmbiguousDivergent && implicitSearchContext.hasErrors) {
84-
context.updateBuffer(implicitSearchContext.errBuffer.filter(err => err.kind == ErrorKinds.Ambiguous || err.kind == ErrorKinds.Divergent))
85-
debuglog("update buffer: " + implicitSearchContext.errBuffer)
84+
context.updateBuffer(implicitSearchContext.reportBuffer.errors.filter(err => err.kind == ErrorKinds.Ambiguous || err.kind == ErrorKinds.Divergent))
85+
debuglog("update buffer: " + implicitSearchContext.reportBuffer.errors)
8686
}
8787
printInference("[infer implicit] inferred " + result)
8888
context.undetparams = context.undetparams filterNot result.subst.from.contains
@@ -584,9 +584,11 @@ trait Implicits {
584584
)
585585
case _ => fallback
586586
}
587-
if (context.hasErrors) {
588-
log("implicit adapt failed: " + context.errBuffer.head.errMsg)
589-
return fail(context.errBuffer.head.errMsg)
587+
context.firstError match { // using match rather than foreach to avoid non local return.
588+
case Some(err) =>
589+
log("implicit adapt failed: " + err.errMsg)
590+
return fail(err.errMsg)
591+
case None =>
590592
}
591593

592594
if (Statistics.canEnable) Statistics.incCounter(typedImplicits)
@@ -609,7 +611,7 @@ trait Implicits {
609611
}
610612

611613
if (context.hasErrors)
612-
fail("hasMatchingSymbol reported error: " + context.errBuffer.head.errMsg)
614+
fail("hasMatchingSymbol reported error: " + context.firstError.get.errMsg)
613615
else if (isLocal && !hasMatchingSymbol(itree1))
614616
fail("candidate implicit %s is shadowed by %s".format(
615617
info.sym.fullLocationString, itree1.symbol.fullLocationString))
@@ -632,8 +634,11 @@ trait Implicits {
632634

633635
// #2421: check that we correctly instantiated type parameters outside of the implicit tree:
634636
checkBounds(itree2, NoPrefix, NoSymbol, undetParams, targs, "inferred ")
635-
if (context.hasErrors)
636-
return fail("type parameters weren't correctly instantiated outside of the implicit tree: " + context.errBuffer.head.errMsg)
637+
context.firstError match {
638+
case Some(err) =>
639+
return fail("type parameters weren't correctly instantiated outside of the implicit tree: " + err.errMsg)
640+
case None =>
641+
}
637642

638643
// filter out failures from type inference, don't want to remove them from undetParams!
639644
// we must be conservative in leaving type params in undetparams
@@ -668,13 +673,14 @@ trait Implicits {
668673
case t => t
669674
}
670675

671-
if (context.hasErrors)
672-
fail("typing TypeApply reported errors for the implicit tree: " + context.errBuffer.head.errMsg)
673-
else {
674-
val result = new SearchResult(itree2, subst)
675-
if (Statistics.canEnable) Statistics.incCounter(foundImplicits)
676-
printInference("[success] found %s for pt %s".format(result, ptInstantiated))
677-
result
676+
context.firstError match {
677+
case Some(err) =>
678+
fail("typing TypeApply reported errors for the implicit tree: " + err.errMsg)
679+
case None =>
680+
val result = new SearchResult(itree2, subst)
681+
if (Statistics.canEnable) Statistics.incCounter(foundImplicits)
682+
printInference("[success] found %s for pt %s".format(result, ptInstantiated))
683+
result
678684
}
679685
}
680686
else fail("incompatible: %s does not match expected type %s".format(itree2.tpe, ptInstantiated))
@@ -828,7 +834,7 @@ trait Implicits {
828834
case sr if sr.isFailure =>
829835
// We don't want errors that occur during checking implicit info
830836
// to influence the check of further infos.
831-
context.condBufferFlush(_.kind != ErrorKinds.Divergent)
837+
context.reportBuffer.retainErrors(ErrorKinds.Divergent)
832838
rankImplicits(is, acc)
833839
case newBest =>
834840
best = newBest
@@ -1085,8 +1091,10 @@ trait Implicits {
10851091

10861092
try {
10871093
val tree1 = typedPos(pos.focus)(arg)
1088-
if (context.hasErrors) processMacroExpansionError(context.errBuffer.head.errPos, context.errBuffer.head.errMsg)
1089-
else new SearchResult(tree1, EmptyTreeTypeSubstituter)
1094+
context.firstError match {
1095+
case Some(err) => processMacroExpansionError(err.errPos, err.errMsg)
1096+
case None => new SearchResult(tree1, EmptyTreeTypeSubstituter)
1097+
}
10901098
} catch {
10911099
case ex: TypeError =>
10921100
processMacroExpansionError(ex.pos, ex.msg)

src/compiler/scala/tools/nsc/typechecker/Infer.scala

Lines changed: 26 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -914,19 +914,28 @@ trait Infer extends Checkable {
914914
}
915915

916916
/**
917-
* Todo: Try to make isApplicable always safe (i.e. not cause TypeErrors).
918-
* The chance of TypeErrors should be reduced through context errors
917+
* Are arguments of the given types applicable to `ftpe`? Type argument inference
918+
* is tried twice: firstly with the given expected type, and secondly with `WildcardType`.
919919
*/
920+
// Todo: Try to make isApplicable always safe (i.e. not cause TypeErrors).
921+
// The chance of TypeErrors should be reduced through context errors
920922
private[typechecker] def isApplicableSafe(undetparams: List[Symbol], ftpe: Type,
921923
argtpes0: List[Type], pt: Type): Boolean = {
922-
val silentContext = context.makeSilent(reportAmbiguousErrors = false)
923-
val typer0 = newTyper(silentContext)
924-
val res1 = typer0.infer.isApplicable(undetparams, ftpe, argtpes0, pt)
925-
if (pt != WildcardType && silentContext.hasErrors) {
926-
silentContext.flushBuffer()
927-
val res2 = typer0.infer.isApplicable(undetparams, ftpe, argtpes0, WildcardType)
928-
if (silentContext.hasErrors) false else res2
929-
} else res1
924+
final case class Result(error: Boolean, applicable: Boolean)
925+
def isApplicableWithExpectedType(pt0: Type): Result = {
926+
val silentContext = context.makeSilent(reportAmbiguousErrors = false)
927+
val applicable = newTyper(silentContext).infer.isApplicable(undetparams, ftpe, argtpes0, pt0)
928+
Result(silentContext.hasErrors, applicable)
929+
}
930+
val canSecondTry = pt != WildcardType
931+
val firstTry = isApplicableWithExpectedType(pt)
932+
if (!firstTry.error || !canSecondTry)
933+
firstTry.applicable
934+
else {
935+
val secondTry = isApplicableWithExpectedType(WildcardType)
936+
// TODO `!secondTry.error &&` was faithfully replicated as part of the refactoring, but mayberedundant.
937+
!secondTry.error && secondTry.applicable
938+
}
930939
}
931940

932941
/** Is type `ftpe1` strictly more specific than type `ftpe2`
@@ -1535,16 +1544,6 @@ trait Infer extends Checkable {
15351544
}
15361545
}
15371546

1538-
@inline private def inSilentMode(context: Context)(expr: => Boolean): Boolean = {
1539-
val oldState = context.state
1540-
context.setBufferErrors()
1541-
val res = expr
1542-
val contextWithErrors = context.hasErrors
1543-
context.flushBuffer()
1544-
context.restoreState(oldState)
1545-
res && !contextWithErrors
1546-
}
1547-
15481547
// Checks against the name of the parameter and also any @deprecatedName.
15491548
private def paramMatchesName(param: Symbol, name: Name) =
15501549
param.name == name || param.deprecatedParamName.exists(_ == name)
@@ -1613,7 +1612,7 @@ trait Infer extends Checkable {
16131612
}
16141613
def followType(sym: Symbol) = followApply(pre memberType sym)
16151614
def bestForExpectedType(pt: Type, isLastTry: Boolean): Unit = {
1616-
val applicable0 = alts filter (alt => inSilentMode(context)(isApplicable(undetparams, followType(alt), argtpes, pt)))
1615+
val applicable0 = alts filter (alt => context inSilentMode (isApplicable(undetparams, followType(alt), argtpes, pt)))
16171616
val applicable = overloadsToConsiderBySpecificity(applicable0, argtpes, varargsStar)
16181617
val ranked = bestAlternatives(applicable)((sym1, sym2) =>
16191618
isStrictlyMoreSpecific(followType(sym1), followType(sym2), sym1, sym2)
@@ -1623,8 +1622,8 @@ trait Infer extends Checkable {
16231622
case best :: Nil => tree setSymbol best setType (pre memberType best) // success
16241623
case Nil if pt eq WildcardType => NoBestMethodAlternativeError(tree, argtpes, pt, isLastTry) // failed
16251624
case Nil => bestForExpectedType(WildcardType, isLastTry) // failed, but retry with WildcardType
1626-
}
1627-
}
1625+
}
1626+
}
16281627
// This potentially makes up to four attempts: tryTwice may execute
16291628
// with and without views enabled, and bestForExpectedType will try again
16301629
// with pt = WildcardType if it fails with pt != WildcardType.
@@ -1640,7 +1639,7 @@ trait Infer extends Checkable {
16401639
*/
16411640
def tryTwice(infer: Boolean => Unit): Unit = {
16421641
if (context.implicitsEnabled) {
1643-
val saved = context.state
1642+
val savedContextMode = context.contextMode
16441643
var fallback = false
16451644
context.setBufferErrors()
16461645
// We cache the current buffer because it is impossible to
@@ -1654,17 +1653,17 @@ trait Infer extends Checkable {
16541653
context.withImplicitsDisabled(infer(false))
16551654
if (context.hasErrors) {
16561655
fallback = true
1657-
context.restoreState(saved)
1656+
context.contextMode = savedContextMode
16581657
context.flushBuffer()
16591658
infer(true)
16601659
}
16611660
} catch {
16621661
case ex: CyclicReference => throw ex
16631662
case ex: TypeError => // recoverable cyclic references
1664-
context.restoreState(saved)
1663+
context.contextMode = savedContextMode
16651664
if (!fallback) infer(true) else ()
16661665
} finally {
1667-
context.restoreState(saved)
1666+
context.contextMode = savedContextMode
16681667
context.updateBuffer(errorsToRestore)
16691668
}
16701669
}

src/compiler/scala/tools/nsc/typechecker/Macros.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -769,12 +769,12 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces {
769769
if (macroDebugVerbose) println(s"typecheck #1 (against expectedTpe = $expectedTpe): $expanded")
770770
val expanded1 = typer.context.withImplicitsEnabled(typer.typed(expanded, mode, expectedTpe))
771771
if (expanded1.isErrorTyped) {
772-
if (macroDebugVerbose) println(s"typecheck #1 has failed: ${typer.context.errBuffer}")
772+
if (macroDebugVerbose) println(s"typecheck #1 has failed: ${typer.context.reportBuffer.errors}")
773773
expanded1
774774
} else {
775775
if (macroDebugVerbose) println(s"typecheck #2 (against pt = $pt): $expanded1")
776776
val expanded2 = typer.context.withImplicitsEnabled(super.onSuccess(expanded1))
777-
if (macroDebugVerbose && expanded2.isErrorTyped) println(s"typecheck #2 has failed: ${typer.context.errBuffer}")
777+
if (macroDebugVerbose && expanded2.isErrorTyped) println(s"typecheck #2 has failed: ${typer.context.reportBuffer.errors}")
778778
expanded2
779779
}
780780
}

src/compiler/scala/tools/nsc/typechecker/Namers.scala

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@ trait Namers extends MethodSynthesis {
4747

4848
private class NormalNamer(context: Context) extends Namer(context)
4949
def newNamer(context: Context): Namer = new NormalNamer(context)
50-
def newNamerFor(context: Context, tree: Tree): Namer = newNamer(context.makeNewScope(tree, tree.symbol))
5150

5251
abstract class Namer(val context: Context) extends MethodSynth with NamerContextErrors { thisNamer =>
5352
// overridden by the presentation compiler
@@ -254,7 +253,7 @@ trait Namers extends MethodSynthesis {
254253
case DocDef(_, defn) => enterSym(defn)
255254
case tree @ Import(_, _) =>
256255
assignSymbol(tree)
257-
returnContext = context.makeNewImport(tree)
256+
returnContext = context.make(tree)
258257
case _ =>
259258
}
260259
returnContext
@@ -1629,7 +1628,7 @@ trait Namers extends MethodSynthesis {
16291628
// @M an abstract type's type parameters are entered.
16301629
// TODO: change to isTypeMember ?
16311630
if (defnSym.isAbstractType)
1632-
newNamerFor(ctx, tree) enterSyms tparams //@M
1631+
newNamer(ctx.makeNewScope(tree, tree.symbol)) enterSyms tparams //@M
16331632
restp complete sym
16341633
}
16351634
}

src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala

Lines changed: 7 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ trait NamesDefaults { self: Analyzer =>
1919
import global._
2020
import definitions._
2121
import NamesDefaultsErrorsGen._
22+
import treeInfo.WildcardStarArg
2223

2324
// Default getters of constructors are added to the companion object in the
2425
// typeCompleter of the constructor (methodSig). To compute the signature,
@@ -278,8 +279,8 @@ trait NamesDefaults { self: Analyzer =>
278279
val repeated = isScalaRepeatedParamType(paramTpe)
279280
val argTpe = (
280281
if (repeated) arg match {
281-
case Typed(expr, Ident(tpnme.WILDCARD_STAR)) => expr.tpe
282-
case _ => seqType(arg.tpe)
282+
case WildcardStarArg(expr) => expr.tpe
283+
case _ => seqType(arg.tpe)
283284
}
284285
else
285286
// Note stabilizing can lead to a non-conformant argument when existentials are involved, e.g. neg/t3507-old.scala, hence the filter.
@@ -302,11 +303,8 @@ trait NamesDefaults { self: Analyzer =>
302303
} else {
303304
new ChangeOwnerTraverser(context.owner, sym) traverse arg // fixes #4502
304305
if (repeated) arg match {
305-
case Typed(expr, Ident(tpnme.WILDCARD_STAR)) =>
306-
expr
307-
case _ =>
308-
val factory = Select(gen.mkAttributedRef(SeqModule), nme.apply)
309-
blockTyper.typed(Apply(factory, List(resetLocalAttrs(arg))))
306+
case WildcardStarArg(expr) => expr
307+
case _ => blockTyper typed gen.mkSeqApply(resetLocalAttrs(arg))
310308
} else arg
311309
}
312310
Some(atPos(body.pos)(ValDef(sym, body).setType(NoType)))
@@ -451,20 +449,6 @@ trait NamesDefaults { self: Analyzer =>
451449
} else NoSymbol
452450
}
453451

454-
private def savingUndeterminedTParams[T](context: Context)(fn: List[Symbol] => T): T = {
455-
val savedParams = context.extractUndetparams()
456-
val savedReporting = context.ambiguousErrors
457-
458-
context.setAmbiguousErrors(false)
459-
try fn(savedParams)
460-
finally {
461-
context.setAmbiguousErrors(savedReporting)
462-
//@M note that we don't get here when an ambiguity was detected (during the computation of res),
463-
// as errorTree throws an exception
464-
context.undetparams = savedParams
465-
}
466-
}
467-
468452
/** A full type check is very expensive; let's make sure there's a name
469453
* somewhere which could potentially be ambiguous before we go that route.
470454
*/
@@ -479,7 +463,8 @@ trait NamesDefaults { self: Analyzer =>
479463
// def f[T](x: T) = x
480464
// var x = 0
481465
// f(x = 1) << "x = 1" typechecks with expected type WildcardType
482-
savingUndeterminedTParams(context) { udp =>
466+
val udp = context.undetparams
467+
context.savingUndeterminedTypeParams(reportAmbiguous = false) {
483468
val subst = new SubstTypeMap(udp, udp map (_ => WildcardType)) {
484469
override def apply(tp: Type): Type = super.apply(tp match {
485470
case TypeRef(_, ByNameParamClass, x :: Nil) => x

src/compiler/scala/tools/nsc/typechecker/RefChecks.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1591,7 +1591,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
15911591
enterReference(tree.pos, tpt.tpe.typeSymbol)
15921592
tree
15931593

1594-
case Typed(_, Ident(tpnme.WILDCARD_STAR)) if !isRepeatedParamArg(tree) =>
1594+
case treeInfo.WildcardStarArg(_) if !isRepeatedParamArg(tree) =>
15951595
unit.error(tree.pos, "no `: _*' annotation allowed here\n"+
15961596
"(such annotations are only allowed in arguments to *-parameters)")
15971597
tree

0 commit comments

Comments
 (0)