diff options
author | Jason Zaugg <jzaugg@gmail.com> | 2015-02-17 15:21:03 +1000 |
---|---|---|
committer | Jason Zaugg <jzaugg@gmail.com> | 2015-02-17 15:53:20 +1000 |
commit | a8ec6c97ea7edbf25ffffe2e798b2deedcd5955f (patch) | |
tree | e5070955dd45536a1804606af9d6d380de4c2036 /test/files/presentation/infix-completion2.check | |
parent | 5a89475526fc91f677d7002b6063bef9e549f0cc (diff) | |
download | scala-a8ec6c97ea7edbf25ffffe2e798b2deedcd5955f.tar.gz scala-a8ec6c97ea7edbf25ffffe2e798b2deedcd5955f.tar.bz2 scala-a8ec6c97ea7edbf25ffffe2e798b2deedcd5955f.zip |
SI-9153 More complete and stable results for completions
Three items of background are needed to understand this bug.
1. When typechecking an application like `qual.m({stats; expr})`, the
argument is typechecked using the formal parameter type of `m` as the
expected type. If this fails with a type error located within in
`expr`, the typer instead re-typechecks under `ContextMode.ReTyping`
without an expected type, and then searches for an implicit adaptation
to enable `view(qual).m(args)`. Under this mode, `Typer#typed1`
clears the type of incoming trees.
2. The presentation compiler performs targetted operations like
type completions by:
- typechecking the enclosing tree, registering all typechecker
`Context`s created in the process (`registerContext`)
- finding the smallest enclosing `Context` around the target
position (`doLocateContext`)
- Using this context to perform implicit search, which can
contribute members to the completion. (`applicableViews` within
`interactive.Global#typeMembers`)
3. When verifiying whether or not a candidate implicit is applicable
as a view from `F => T`, implicit search typechecks a dummy call
of the form `q"candiate(${Ident("<argument>").setType(typeOf[F])})".
Now, picture yourself at the nexus of these three storms.
In the enclosed test case, we search for completions at:
x + 1.<caret>
1. Because the code is incomplete, the application of `Int#+`
doesn't typecheck, and the typer also tries to adapt `x` to a
method applicable to the re-typechecked argument.
2. This process registers a context with `retypechecking` set to
true. (If multiple contexts at the same position are registered,
the last one wins.)
3. Implicit search uses this context to typecheck
`Predef.Ensuring(<argument>.setType(Int))`, but the argument
is promptly stripped of its type and retypechecking fails
as there is no definition named `<argument>` in scope.
As such, we missed out on extension methods, like `ensuring` in the
list of completions.
This commit changes the presentation compiler to turn off retyping
mode in the context before starting to work with it. (Are the other
modes that might cause similar bugs?)
Once I made that change, I noticed that the results the enclosed test
was not stable. I tracked this down to the use of a `HashMap` to
carry the applicable implicit views, together with the way that
the presentation compiler removes duplicates. This commit
switched to a `LinkedHashMap`.
Diffstat (limited to 'test/files/presentation/infix-completion2.check')
-rw-r--r-- | test/files/presentation/infix-completion2.check | 212 |
1 files changed, 212 insertions, 0 deletions
diff --git a/test/files/presentation/infix-completion2.check b/test/files/presentation/infix-completion2.check new file mode 100644 index 0000000000..d61ca5e571 --- /dev/null +++ b/test/files/presentation/infix-completion2.check @@ -0,0 +1,212 @@ +reload: Snippet.scala + +askTypeCompletion at Snippet.scala(1,34) +================================================================================ +[response] askTypeCompletion at (1,34) +retrieved 212 members +[inaccessible] protected def integralNum: math.Numeric.DoubleAsIfIntegral.type +[inaccessible] protected def num: math.Numeric.DoubleIsFractional.type +[inaccessible] protected def ord: math.Ordering.Double.type +[inaccessible] protected def unifiedPrimitiveEquals(x: Any): Boolean +[inaccessible] protected def unifiedPrimitiveHashcode(): Int +[inaccessible] protected[package lang] def clone(): Object +[inaccessible] protected[package lang] def finalize(): Unit +def !=(x: Byte): Boolean +def !=(x: Char): Boolean +def !=(x: Double): Boolean +def !=(x: Float): Boolean +def !=(x: Int): Boolean +def !=(x: Long): Boolean +def !=(x: Short): Boolean +def %(x: Byte): Int +def %(x: Char): Int +def %(x: Double): Double +def %(x: Float): Float +def %(x: Int): Int +def %(x: Long): Long +def %(x: Short): Int +def &(x: Byte): Int +def &(x: Char): Int +def &(x: Int): Int +def &(x: Long): Long +def &(x: Short): Int +def *(x: Byte): Int +def *(x: Char): Int +def *(x: Double): Double +def *(x: Float): Float +def *(x: Int): Int +def *(x: Long): Long +def *(x: Short): Int +def +(x: Byte): Int +def +(x: Char): Int +def +(x: Double): Double +def +(x: Float): Float +def +(x: Int): Int +def +(x: Long): Long +def +(x: Short): Int +def +(x: String): String +def -(x: Byte): Int +def -(x: Char): Int +def -(x: Double): Double +def -(x: Float): Float +def -(x: Int): Int +def -(x: Long): Long +def -(x: Short): Int +def ->[B](y: B): (Int, B) +def /(x: Byte): Int +def /(x: Char): Int +def /(x: Double): Double +def /(x: Float): Float +def /(x: Int): Int +def /(x: Long): Long +def /(x: Short): Int +def <(x: Byte): Boolean +def <(x: Char): Boolean +def <(x: Double): Boolean +def <(x: Float): Boolean +def <(x: Int): Boolean +def <(x: Long): Boolean +def <(x: Short): Boolean +def <<(x: Int): Int +def <<(x: Long): Int +def <=(x: Byte): Boolean +def <=(x: Char): Boolean +def <=(x: Double): Boolean +def <=(x: Float): Boolean +def <=(x: Int): Boolean +def <=(x: Long): Boolean +def <=(x: Short): Boolean +def ==(x: Byte): Boolean +def ==(x: Char): Boolean +def ==(x: Double): Boolean +def ==(x: Float): Boolean +def ==(x: Int): Boolean +def ==(x: Long): Boolean +def ==(x: Short): Boolean +def >(x: Byte): Boolean +def >(x: Char): Boolean +def >(x: Double): Boolean +def >(x: Float): Boolean +def >(x: Int): Boolean +def >(x: Long): Boolean +def >(x: Short): Boolean +def >=(x: Byte): Boolean +def >=(x: Char): Boolean +def >=(x: Double): Boolean +def >=(x: Float): Boolean +def >=(x: Int): Boolean +def >=(x: Long): Boolean +def >=(x: Short): Boolean +def >>(x: Int): Int +def >>(x: Long): Int +def >>>(x: Int): Int +def >>>(x: Long): Int +def ^(x: Byte): Int +def ^(x: Char): Int +def ^(x: Int): Int +def ^(x: Long): Long +def ^(x: Short): Int +def byteValue(): Byte +def ceil: Double +def compare(y: Double): Int +def compare(y: Float): Int +def compare(y: Int): Int +def compare(y: Long): Int +def compareTo(that: Double): Int +def compareTo(that: Float): Int +def compareTo(that: Int): Int +def compareTo(that: Long): Int +def compareTo(x$1: Double): Int +def compareTo(x$1: Float): Int +def compareTo(x$1: Integer): Int +def compareTo(x$1: Long): Int +def doubleValue(): Double +def ensuring(cond: Boolean): Int +def ensuring(cond: Boolean,msg: => Any): Int +def ensuring(cond: Int => Boolean): Int +def ensuring(cond: Int => Boolean,msg: => Any): Int +def equals(x$1: Any): Boolean +def floatValue(): Float +def floor: Double +def formatted(fmtstr: String): String +def hashCode(): Int +def intValue(): Int +def isInfinite(): Boolean +def isInfinity: Boolean +def isNaN(): Boolean +def isNegInfinity: Boolean +def isPosInfinity: Boolean +def isValidLong: Boolean +def longValue(): Long +def round: Long +def shortValue(): Short +def to(end: Double): Range.Partial[Double,scala.collection.immutable.NumericRange[Double]] +def to(end: Double,step: Double): scala.collection.immutable.NumericRange.Inclusive[Double] +def to(end: Float): Range.Partial[Float,scala.collection.immutable.NumericRange[Float]] +def to(end: Float,step: Float): scala.collection.immutable.NumericRange.Inclusive[Float] +def to(end: Int): scala.collection.immutable.Range.Inclusive +def to(end: Int,step: Int): scala.collection.immutable.Range.Inclusive +def to(end: Long): scala.collection.immutable.NumericRange.Inclusive[Long] +def to(end: Long,step: Long): scala.collection.immutable.NumericRange.Inclusive[Long] +def toBinaryString: String +def toByte: Byte +def toChar: Char +def toDegrees: Double +def toDouble: Double +def toFloat: Float +def toHexString: String +def toInt: Int +def toLong: Long +def toOctalString: String +def toRadians: Double +def toShort: Short +def toString(): String +def unary_+: Int +def unary_-: Int +def unary_~: Int +def underlying(): AnyRef +def until(end: Double): Range.Partial[Double,scala.collection.immutable.NumericRange[Double]] +def until(end: Double,step: Double): scala.collection.immutable.NumericRange.Exclusive[Double] +def until(end: Float): Range.Partial[Float,scala.collection.immutable.NumericRange[Float]] +def until(end: Float,step: Float): scala.collection.immutable.NumericRange.Exclusive[Float] +def until(end: Int): scala.collection.immutable.Range +def until(end: Int,step: Int): scala.collection.immutable.Range +def until(end: Long): scala.collection.immutable.NumericRange.Exclusive[Long] +def until(end: Long,step: Long): scala.collection.immutable.NumericRange.Exclusive[Long] +def |(x: Byte): Int +def |(x: Char): Int +def |(x: Int): Int +def |(x: Long): Long +def |(x: Short): Int +def →[B](y: B): (Int, B) +final def !=(x$1: Any): Boolean +final def ##(): Int +final def ==(x$1: Any): Boolean +final def asInstanceOf[T0]: T0 +final def eq(x$1: AnyRef): Boolean +final def isInstanceOf[T0]: Boolean +final def ne(x$1: AnyRef): Boolean +final def notify(): Unit +final def notifyAll(): Unit +final def synchronized[T0](x$1: T0): T0 +final def wait(): Unit +final def wait(x$1: Long): Unit +final def wait(x$1: Long,x$2: Int): Unit +override def abs: Double +override def isValidByte: Boolean +override def isValidChar: Boolean +override def isValidInt: Boolean +override def isValidShort: Boolean +override def isWhole(): Boolean +override def max(that: Double): Double +override def max(that: Float): Float +override def max(that: Int): Int +override def max(that: Long): Long +override def min(that: Double): Double +override def min(that: Float): Float +override def min(that: Int): Int +override def min(that: Long): Long +override def signum: Int +private[this] val self: Double +type ResultWithoutStep = Range.Partial[Double,scala.collection.immutable.NumericRange[Double]] +================================================================================ |