From a89000be9f5b6506bcd891bd076700a9d1e79d01 Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Mon, 2 Dec 2013 17:14:41 +0100 Subject: SI-8023 Fix symbol-completion-order type var pattern bug Removing the `isComplete` check altogether leads to cycles in, for instatnce, F-bound type parameters: trait LSO[+A, +Repr <: LSO[A, Repr]] // error: illegal cyclic reference involving type Repr But, I believe that we can (and must) eagerly initialize the type parameter symbols if we are typechecking a pattern. While this appeared to regress in 2.11.x, but the problem was in fact dormant and was merely uncovered in the fix for SI-7756, 3df1d77fc. --- test/files/pos/t8023.scala | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 test/files/pos/t8023.scala (limited to 'test/files') diff --git a/test/files/pos/t8023.scala b/test/files/pos/t8023.scala new file mode 100644 index 0000000000..86824084ed --- /dev/null +++ b/test/files/pos/t8023.scala @@ -0,0 +1,22 @@ +import language._ + + +object Test { + def foo = (null: Any) match { + case a: A[k] => + // error: kinds of the type arguments (k) do not conform to the + // expected kinds of the type parameters (type K) in class B. + new B[k]() + } +} + +class A[K[L[_]]] + +class B[K[M[_]]] + + +object Test2 { + def foo = (null: Any) match { + case a: A[k] => new B[k]() // this one worked before as the info of `A` was complete + } +} -- cgit v1.2.3 From d0aaa86a9fe20e00f0cfa4fd1154126579933fb7 Mon Sep 17 00:00:00 2001 From: Jason Zaugg Date: Tue, 3 Dec 2013 12:32:59 +0100 Subject: SI-8023 Address review comments around typedHigherKindedType - Make `WildCardType` kind polymorphic - Factory methods for expected kinds. They are still just `Type`-s, though. - Check if the type parameter is initialized, rather than its owner. - Take advantage of these to cleanup `typedAppliedTypeTree` TODO: is this comment totally accurate? If so, should we refactor `Kind.FromParams(tparams)` to `Kind.Arity(tparams.length)`? // @M: kind-arity checking is done here and in adapt, // full kind-checking is in checkKindBounds (in Infer) --- .../scala/tools/nsc/typechecker/Typers.scala | 32 ++++++++++------------ src/reflect/scala/reflect/internal/Kinds.scala | 2 ++ test/files/pos/t8023b.scala | 2 ++ 3 files changed, 18 insertions(+), 18 deletions(-) create mode 100644 test/files/pos/t8023b.scala (limited to 'test/files') diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index a8d332f96a..c947fba37e 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -3835,7 +3835,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper // as we don't know which alternative to choose... here we do map2Conserve(args, tparams) { //@M! the polytype denotes the expected kind - (arg, tparam) => typedHigherKindedType(arg, mode, GenPolyType(tparam.typeParams, AnyTpe)) + (arg, tparam) => typedHigherKindedType(arg, mode, Kind.FromParams(tparam.typeParams)) } } else // @M: there's probably something wrong when args.length != tparams.length... (triggered by bug #320) // Martin, I'm using fake trees, because, if you use args or arg.map(typedType), @@ -4880,20 +4880,17 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper if (sameLength(tparams, args)) { // @M: kind-arity checking is done here and in adapt, full kind-checking is in checkKindBounds (in Infer) val args1 = map2Conserve(args, tparams) { (arg, tparam) => - //@M! the polytype denotes the expected kind - def pt = GenPolyType(tparam.typeParams, AnyTpe) - - // if symbol hasn't been fully loaded, can't check kind-arity - // ... except, if we're in a pattern, where we can and must (SI-8023) - if (mode.typingPatternOrTypePat) { - tparam.initialize - typedHigherKindedType(arg, mode, pt) + def ptParams = Kind.FromParams(tparam.typeParams) + + // if symbol hasn't been fully loaded, can't check kind-arity except when we're in a pattern, + // where we can (we can't take part in F-Bounds) and must (SI-8023) + val pt = if (mode.typingPatternOrTypePat) { + tparam.initialize; ptParams } - else if (isComplete) - typedHigherKindedType(arg, mode, pt) - else - // This overload (without pt) allows type constructors, as we don't don't know the allowed kind. - typedHigherKindedType(arg, mode) + else if (isComplete) ptParams + else Kind.Wildcard + + typedHigherKindedType(arg, mode, pt) } val argtypes = args1 map (_.tpe) @@ -5080,8 +5077,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper // @M maybe the well-kindedness check should be done when checking the type arguments conform to the type parameters' bounds? val args1 = if (sameLength(args, tparams)) map2Conserve(args, tparams) { - //@M! the polytype denotes the expected kind - (arg, tparam) => typedHigherKindedType(arg, mode, GenPolyType(tparam.typeParams, AnyTpe)) + (arg, tparam) => typedHigherKindedType(arg, mode, Kind.FromParams(tparam.typeParams)) } else { //@M this branch is correctly hit for an overloaded polymorphic type. It also has to handle erroneous cases. @@ -5451,9 +5447,9 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper /** Types a (fully parameterized) type tree */ def typedType(tree: Tree): Tree = typedType(tree, NOmode) - /** Types a higher-kinded type tree -- pt denotes the expected kind*/ + /** Types a higher-kinded type tree -- pt denotes the expected kind and must be one of `Kind.WildCard` and `Kind.FromParams` */ def typedHigherKindedType(tree: Tree, mode: Mode, pt: Type): Tree = - if (pt.typeParams.isEmpty) typedType(tree, mode) // kind is known and it's * + if (pt != Kind.Wildcard && pt.typeParams.isEmpty) typedType(tree, mode) // kind is known and it's * else context withinTypeConstructorAllowed typed(tree, NOmode, pt) def typedHigherKindedType(tree: Tree, mode: Mode): Tree = diff --git a/src/reflect/scala/reflect/internal/Kinds.scala b/src/reflect/scala/reflect/internal/Kinds.scala index d48a6c6322..8ae201f045 100644 --- a/src/reflect/scala/reflect/internal/Kinds.scala +++ b/src/reflect/scala/reflect/internal/Kinds.scala @@ -326,6 +326,8 @@ trait Kinds { private[internal] object StringState { def empty: StringState = StringState(Seq()) } + def FromParams(tparams: List[Symbol]): Type = GenPolyType(tparams, AnyTpe) + def Wildcard: Type = WildcardType } class ProperTypeKind(val bounds: TypeBounds) extends Kind { import Kind.StringState diff --git a/test/files/pos/t8023b.scala b/test/files/pos/t8023b.scala new file mode 100644 index 0000000000..94c9b2f8d2 --- /dev/null +++ b/test/files/pos/t8023b.scala @@ -0,0 +1,2 @@ +// this fails with naive attempts to fix SI-8023 +trait T[A <: T[A]] -- cgit v1.2.3