From bc5ac3dc9a03553072f69d1117ea2389473acd4a Mon Sep 17 00:00:00 2001 From: Adriaan Moors Date: Thu, 8 Jul 2010 15:59:00 +0000 Subject: closes #3374. review by odersky --- .../scala/tools/nsc/typechecker/Infer.scala | 26 +++++++++++++++++----- .../scala/tools/nsc/typechecker/Namers.scala | 19 +--------------- test/files/neg/bug1275.check | 8 ++++--- test/files/neg/bug1275.scala | 26 ++++++++++------------ test/files/pos/t3374.scala | 6 +++++ 5 files changed, 44 insertions(+), 41 deletions(-) create mode 100644 test/files/pos/t3374.scala diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index ba0b8317b5..1993a8c23f 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -1040,12 +1040,20 @@ trait Infer { */ def checkKindBounds(tparams: List[Symbol], targs: List[Type], pre: Type, owner: Symbol): List[String] = { def transform(tp: Type, clazz: Symbol): Type = tp.asSeenFrom(pre, clazz) // instantiate type params that come from outside the abstract type we're currently checking + def transformedBounds(p: Symbol, o: Symbol) = transform(p.info.instantiateTypeParams(tparams, targs).bounds, o) // check that the type parameters hkargs to a higher-kinded type conform to the expected params hkparams - def checkKindBoundsHK(hkargs: List[Symbol], arg: Symbol, param: Symbol, paramowner: Symbol): (List[(Symbol, Symbol)], List[(Symbol, Symbol)], List[(Symbol, Symbol)]) = { + def checkKindBoundsHK(hkargs: List[Symbol], arg: Symbol, param: Symbol, paramowner: Symbol, underHKParams: List[Symbol], withHKArgs: List[Symbol]): (List[(Symbol, Symbol)], List[(Symbol, Symbol)], List[(Symbol, Symbol)]) = { + def bindHKParams(tp: Type) = tp.substSym(underHKParams, withHKArgs) // @M sometimes hkargs != arg.typeParams, the symbol and the type may have very different type parameters val hkparams = param.typeParams + if(printTypings) { + println("checkKindBoundsHK expected: "+ param +" with params "+ hkparams +" by definition in "+ paramowner) + println("checkKindBoundsHK supplied: "+ arg +" with params "+ hkargs +" from "+ owner) + println("checkKindBoundsHK under params: "+ underHKParams +" with args "+ withHKArgs) + } + if(hkargs.length != hkparams.length) { if(arg == AnyClass || arg == NothingClass) (Nil, Nil, Nil) // Any and Nothing are kind-overloaded else (List((arg, param)), Nil, Nil) @@ -1068,10 +1076,16 @@ trait Infer { // substSym(hkparams, hkargs) --> these types are going to be compared as types of kind * // --> their arguments use different symbols, but are conceptually the same // (could also replace the types by polytypes, but can't just strip the symbols, as ordering is lost then) - if (!(transform(hkparam.info.instantiateTypeParams(tparams, targs).bounds.substSym(hkparams, hkargs), paramowner) <:< transform(hkarg.info.bounds, owner))) + if (!(bindHKParams(transformedBounds(hkparam, paramowner)) <:< transform(hkarg.info.bounds, owner))) stricterBound(hkarg, hkparam) + + if(printTypings) { + println("checkKindBoundsHK base case: "+ hkparam +" declared bounds: "+ transformedBounds(hkparam, paramowner) +" after instantiating earlier hkparams: "+ bindHKParams(transformedBounds(hkparam, paramowner))) + println("checkKindBoundsHK base case: "+ hkarg +" has bounds: "+ transform(hkarg.info.bounds, owner)) + } } else { - val (am, vm, sb) = checkKindBoundsHK(hkarg.typeParams, hkarg, hkparam, paramowner) + if(printTypings) println("checkKindBoundsHK recursing to compare params of "+ hkparam +" with "+ hkarg) + val (am, vm, sb) = checkKindBoundsHK(hkarg.typeParams, hkarg, hkparam, paramowner, underHKParams ++ hkparam.typeParams, withHKArgs ++ hkarg.typeParams) arityMismatches(am) varianceMismatches(vm) stricterBounds(sb) @@ -1099,11 +1113,11 @@ trait Infer { val errors = new ListBuffer[String] (tparams zip targs).foreach{ case (tparam, targ) if (targ.isHigherKinded || !tparam.typeParams.isEmpty) => - // @M must use the typeParams of the type targ, not the typeParams of the symbol of targ!! - val tparamsHO = targ.typeParams + // @M must use the typeParams of the type targ, not the typeParams of the symbol of targ!! + val tparamsHO = targ.typeParams val (arityMismatches, varianceMismatches, stricterBounds) = - checkKindBoundsHK(tparamsHO, targ.typeSymbolDirect, tparam, tparam.owner) // NOTE: *not* targ.typeSymbol, which normalizes + checkKindBoundsHK(tparamsHO, targ.typeSymbolDirect, tparam, tparam.owner, tparam.typeParams, tparamsHO) // NOTE: *not* targ.typeSymbol, which normalizes if (!(arityMismatches.isEmpty && varianceMismatches.isEmpty && stricterBounds.isEmpty)){ errors += (targ+"'s type parameters do not match "+tparam+"'s expected parameters: "+ (for ((a, p) <- arityMismatches) diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index 2123a00550..53fb15dbeb 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -1065,24 +1065,7 @@ trait Namers { self: Analyzer => case tp => tp } - - def verifyOverriding(other: Symbol): Boolean = { - if(other.unsafeTypeParams.length != tparamSyms.length) { - context.error(tpsym.pos, - "The kind of "+tpsym.keyString+" "+tpsym.varianceString + tpsym.nameString+ - " does not conform to the expected kind of " + other.defString + other.locationString + ".") - false - } else true - } - - // @M: make sure overriding in refinements respects rudimentary kinding - // have to do this early, as otherwise we might get crashes: (see neg/bug1275.scala) - // suppose some parameterized type member is overridden by a type member w/o params, - // then appliedType will be called on a type that does not expect type args --> crash - if (tpsym.owner.isRefinementClass && // only needed in refinements - !tpsym.allOverriddenSymbols.forall{verifyOverriding(_)}) - ErrorType - else polyType(tparamSyms, tp) + polyType(tparamSyms, tp) } /** Given a case class diff --git a/test/files/neg/bug1275.check b/test/files/neg/bug1275.check index 9f806c0689..40c5d79d27 100644 --- a/test/files/neg/bug1275.check +++ b/test/files/neg/bug1275.check @@ -1,4 +1,6 @@ -bug1275.scala:13: error: The kind of type MyType does not conform to the expected kind of type MyType[+t] <: TestCovariance.Seq[t] in trait Seq. - def span[a, s <: Seq[a] { type MyType <: s } ](xs: s): s = xs f - ^ +bug1275.scala:8: error: type mismatch; + found : xs.MyType[a] + required: s + = xs f // xs: s <: Seq[a]{type MyType <: s } + ^ one error found diff --git a/test/files/neg/bug1275.scala b/test/files/neg/bug1275.scala index e9be13c763..769156fff2 100644 --- a/test/files/neg/bug1275.scala +++ b/test/files/neg/bug1275.scala @@ -1,14 +1,12 @@ -// tested using Scala compiler version 2.6.0-RC1 -- (c) 2002-2010 LAMP/EPFL - -// prompted by "Covariant return types" mailing list question -object TestCovariance { - - // see Type constructor polymorphism in http://www.scala-lang.org/docu/changelog.html - trait Seq[+t] { - type MyType[+t] <: Seq[t] - - def f: MyType[t] - } - - def span[a, s <: Seq[a] { type MyType <: s } ](xs: s): s = xs f -} +object Test { + trait Seq[+t] { + type MyType[+t] <: Seq[t] + def f: MyType[t] + } + + def span[a, s <: Seq[a] { type MyType <: s } ](xs: s): s + = xs f // xs: s <: Seq[a]{type MyType <: s } + // xs.f : xs.MyType[a] <: Seq[a] + // ill-formed type in bound for s: Seq[a] { type MyType <: s } + // refinements aren't checked -- should they? +} \ No newline at end of file diff --git a/test/files/pos/t3374.scala b/test/files/pos/t3374.scala new file mode 100644 index 0000000000..4c0293181d --- /dev/null +++ b/test/files/pos/t3374.scala @@ -0,0 +1,6 @@ +trait Parent { + type Test[A, H[B <: A]] +} +trait Sub extends Parent { + type Test[AS, HS[B <: AS]] = AS +} \ No newline at end of file -- cgit v1.2.3