Skip to content

Commit 358e246

Browse files
committed
Clean up terminology
There are two concepts that were quite close but not exactly the same: - isErroneous, used if a type has errors in any part of it. Usually tested to not show a type with errors in it in diagnostics. - unusableForInference, used if a type (or its alias) has errors that make the type too undiscriminating for overloading resolution or implicit search. Previously, we only used isErroneous in error diagnstics. Using it also for disabling implicit search and resolutions ran into problems. Hence, the new predicate unusableForInference.
1 parent 3b91efb commit 358e246

File tree

4 files changed

+40
-22
lines changed

4 files changed

+40
-22
lines changed

compiler/src/dotty/tools/dotc/core/Types.scala

+18-14
Original file line numberDiff line numberDiff line change
@@ -332,24 +332,28 @@ object Types {
332332
/** Is this type produced as a repair for an error? */
333333
final def isError(using Context): Boolean = stripTypeVar.isInstanceOf[ErrorType]
334334

335-
/** A conservative approximation whether a type might have errors.
336-
* It's OK to predict "no errors" even though errors might be present.
337-
* But one should never force or loop.
335+
/** Is some part of the widened version of this type produced as a repair for an error?
336+
*
338337
*/
339-
def hasErrors(using Context): Boolean = widenDealias match
340-
case AppliedType(tycon, args) => tycon.hasErrors || args.exists(_.hasErrors)
341-
case RefinedType(parent, _, rinfo) => parent.hasErrors || rinfo.hasErrors
342-
case TypeBounds(lo, hi) => lo.hasErrors || hi.hasErrors
343-
case tp: AndOrType => tp.tp1.hasErrors || tp.tp2.hasErrors
344-
case tp: LambdaType => tp.resultType.hasErrors || tp.paramInfos.exists(_.hasErrors)
345-
case WildcardType(optBounds) => optBounds.hasErrors
346-
case _: ErrorType => true
347-
case _ => false
348-
349-
/** Is some part of the widened version of this type produced as a repair for an error? */
350338
def isErroneous(using Context): Boolean =
351339
widen.existsPart(_.isError, forceLazy = false)
352340

341+
/** Is this type unusable for implicit search or overloading resolution
342+
* since it has embedded errors that can match anything? This is weaker and more
343+
* ad-hoc than isErroneous. The main differences are that we always consider aliases
344+
* (since these are relevant for inference or resolution) but never consider prefixes
345+
* (since these often do not constrain the search space anyway).
346+
*/
347+
def unusableForInference(using Context): Boolean = widenDealias match
348+
case AppliedType(tycon, args) => tycon.unusableForInference || args.exists(_.unusableForInference)
349+
case RefinedType(parent, _, rinfo) => parent.unusableForInference || rinfo.unusableForInference
350+
case TypeBounds(lo, hi) => lo.unusableForInference || hi.unusableForInference
351+
case tp: AndOrType => tp.tp1.unusableForInference || tp.tp2.unusableForInference
352+
case tp: LambdaType => tp.resultType.unusableForInference || tp.paramInfos.exists(_.unusableForInference)
353+
case WildcardType(optBounds) => optBounds.unusableForInference
354+
case _: ErrorType => true
355+
case _ => false
356+
353357
/** Does the type carry an annotation that is an instance of `cls`? */
354358
@tailrec final def hasAnnotation(cls: ClassSymbol)(using Context): Boolean = stripTypeVar match {
355359
case AnnotatedType(tp, annot) => (annot matches cls) || (tp hasAnnotation cls)

compiler/src/dotty/tools/dotc/typer/Applications.scala

+2-2
Original file line numberDiff line numberDiff line change
@@ -474,7 +474,7 @@ trait Applications extends Compatibility {
474474

475475
protected def methodType: MethodType = methType.asInstanceOf[MethodType]
476476
private def methString: String =
477-
def infoStr = if methType.hasErrors then "" else i": $methType"
477+
def infoStr = if methType.isErroneous then "" else i": $methType"
478478
i"${err.refStr(methRef)}$infoStr"
479479

480480
/** Re-order arguments to correctly align named arguments */
@@ -1944,7 +1944,7 @@ trait Applications extends Compatibility {
19441944
case _ => false
19451945

19461946
record("resolveOverloaded.narrowedApplicable", candidates.length)
1947-
if pt.hasErrors then
1947+
if pt.unusableForInference then
19481948
// `pt` might have become erroneous by typing arguments of FunProtos.
19491949
// If `pt` is erroneous, don't try to go further; report the error in `pt` instead.
19501950
candidates

compiler/src/dotty/tools/dotc/typer/Implicits.scala

+3-2
Original file line numberDiff line numberDiff line change
@@ -955,8 +955,9 @@ trait Implicits:
955955
if (argument.isEmpty) i"missing implicit parameter of type $pt after typer"
956956
else i"type error: ${argument.tpe} does not conform to $pt${err.whyNoMatchStr(argument.tpe, pt)}")
957957

958-
if pt.hasErrors || !argument.isEmpty && argument.tpe.hasErrors then
959-
return NoMatchingImplicitsFailure
958+
if pt.unusableForInference
959+
|| !argument.isEmpty && argument.tpe.unusableForInference
960+
then return NoMatchingImplicitsFailure
960961

961962
val result0 =
962963
try ImplicitSearch(pt, argument, span).bestImplicit

compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala

+17-4
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,11 @@ object ProtoTypes {
193193
if ((name eq this.name) && (memberProto eq this.memberProto) && (compat eq this.compat)) this
194194
else SelectionProto(name, memberProto, compat, privateOK)
195195

196-
override def hasErrors(using Context): Boolean = memberProto.hasErrors
196+
override def isErroneous(using Context): Boolean =
197+
memberProto.isErroneous
198+
199+
override def unusableForInference(using Context): Boolean =
200+
memberProto.unusableForInference
197201

198202
def map(tm: TypeMap)(using Context): SelectionProto = derivedSelectionProto(name, tm(memberProto), compat)
199203
def fold[T](x: T, ta: TypeAccumulator[T])(using Context): T = ta(x, memberProto)
@@ -405,7 +409,8 @@ object ProtoTypes {
405409
override def isErroneous(using Context): Boolean =
406410
state.typedArgs.tpes.exists(_.isErroneous)
407411

408-
override def hasErrors(using Context): Boolean = state.typedArgs.exists(_.tpe.hasErrors)
412+
override def unusableForInference(using Context): Boolean =
413+
state.typedArgs.exists(_.tpe.unusableForInference)
409414

410415
override def toString: String = s"FunProto(${args mkString ","} => $resultType)"
411416

@@ -457,7 +462,11 @@ object ProtoTypes {
457462
if ((argType eq this.argType) && (resultType eq this.resultType)) this
458463
else ViewProto(argType, resultType)
459464

460-
override def hasErrors(using Context): Boolean = argType.hasErrors || resType.hasErrors
465+
override def isErroneous(using Context): Boolean =
466+
argType.isErroneous || resType.isErroneous
467+
468+
override def unusableForInference(using Context): Boolean =
469+
argType.unusableForInference || resType.unusableForInference
461470

462471
def map(tm: TypeMap)(using Context): ViewProto = derivedViewProto(tm(argType), tm(resultType))
463472

@@ -502,7 +511,11 @@ object ProtoTypes {
502511
if ((targs eq this.targs) && (resType eq this.resType)) this
503512
else PolyProto(targs, resType)
504513

505-
override def hasErrors(using Context): Boolean = targs.exists(_.tpe.hasErrors)
514+
override def isErroneous(using Context): Boolean =
515+
targs.exists(_.tpe.isErroneous)
516+
517+
override def unusableForInference(using Context): Boolean =
518+
targs.exists(_.tpe.unusableForInference)
506519

507520
def map(tm: TypeMap)(using Context): PolyProto =
508521
derivedPolyProto(targs, tm(resultType))

0 commit comments

Comments
 (0)